Mike McCormack | e0df32f | 2000-08-11 21:15:21 +0000 | [diff] [blame] | 1 | #!/usr/bin/perl |
| 2 | |
| 3 | ##################################################################################### |
Alexandre Julliard | 7cae558 | 2002-06-01 02:55:48 +0000 | [diff] [blame] | 4 | # |
Mike McCormack | e0df32f | 2000-08-11 21:15:21 +0000 | [diff] [blame] | 5 | # c2man.pl v0.1 Copyright (C) 2000 Mike McCormack |
| 6 | # |
Alexandre Julliard | 0799c1a | 2002-03-09 23:29:33 +0000 | [diff] [blame] | 7 | # Generates Documents from C source code. |
Mike McCormack | e0df32f | 2000-08-11 21:15:21 +0000 | [diff] [blame] | 8 | # |
| 9 | # Input is source code with specially formatted comments, output |
| 10 | # is man pages. The functionality is meant to be similar to c2man. |
| 11 | # The following is an example provided in the Wine documentation. |
| 12 | # |
Alexandre Julliard | 0799c1a | 2002-03-09 23:29:33 +0000 | [diff] [blame] | 13 | # This library is free software; you can redistribute it and/or |
| 14 | # modify it under the terms of the GNU Lesser General Public |
| 15 | # License as published by the Free Software Foundation; either |
| 16 | # version 2.1 of the License, or (at your option) any later version. |
| 17 | # |
| 18 | # This library is distributed in the hope that it will be useful, |
| 19 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 20 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 21 | # Lesser General Public License for more details. |
| 22 | # |
| 23 | # You should have received a copy of the GNU Lesser General Public |
| 24 | # License along with this library; if not, write to the Free Software |
| 25 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| 26 | # |
Mike McCormack | e0df32f | 2000-08-11 21:15:21 +0000 | [diff] [blame] | 27 | # TODO: |
| 28 | # Write code to generate HTML output with the -Th option. |
| 29 | # Need somebody who knows about TROFF to help touch up the man page generation. |
| 30 | # Parse spec files passed with -w option and generate pages for the functions |
| 31 | # in the spec files only. |
| 32 | # Modify Makefiles to pass multiple C files to speed up man page generation. |
| 33 | # Use nm on the shared libraries specified in the spec files to determine which |
| 34 | # source files should be parsed, and only parse them.(requires wine to be compiled) |
| 35 | # |
| 36 | ##################################################################################### |
| 37 | # Input from C source file: |
Alexandre Julliard | 7cae558 | 2002-06-01 02:55:48 +0000 | [diff] [blame] | 38 | # |
Mike McCormack | e0df32f | 2000-08-11 21:15:21 +0000 | [diff] [blame] | 39 | # /****************************************************************** |
| 40 | # * CopyMetaFile32A (GDI32.23) |
| 41 | # * |
| 42 | # * Copies the metafile corresponding to hSrcMetaFile to either |
| 43 | # * a disk file, if a filename is given, or to a new memory based |
| 44 | # * metafile, if lpFileName is NULL. |
| 45 | # * |
| 46 | # * RETURNS |
| 47 | # * |
| 48 | # * Handle to metafile copy on success, NULL on failure. |
| 49 | # * |
| 50 | # * BUGS |
| 51 | # * |
| 52 | # * Copying to disk returns NULL even if successful. |
| 53 | # */ |
| 54 | # HMETAFILE32 WINAPI CopyMetaFile32A( |
| 55 | # HMETAFILE32 hSrcMetaFile, /* handle of metafile to copy */ |
| 56 | # LPCSTR lpFilename /* filename if copying to a file */ |
| 57 | # ) { ... } |
| 58 | # |
| 59 | ##################################################################################### |
| 60 | # Output after processing with nroff -man |
Alexandre Julliard | 7cae558 | 2002-06-01 02:55:48 +0000 | [diff] [blame] | 61 | # |
Mike McCormack | e0df32f | 2000-08-11 21:15:21 +0000 | [diff] [blame] | 62 | # CopyMetaFileA(3w) CopyMetaFileA(3w) |
Alexandre Julliard | 7cae558 | 2002-06-01 02:55:48 +0000 | [diff] [blame] | 63 | # |
| 64 | # |
Mike McCormack | e0df32f | 2000-08-11 21:15:21 +0000 | [diff] [blame] | 65 | # NAME |
| 66 | # CopyMetaFileA - CopyMetaFile32A (GDI32.23) |
Alexandre Julliard | 7cae558 | 2002-06-01 02:55:48 +0000 | [diff] [blame] | 67 | # |
Mike McCormack | e0df32f | 2000-08-11 21:15:21 +0000 | [diff] [blame] | 68 | # SYNOPSIS |
| 69 | # HMETAFILE32 CopyMetaFileA |
| 70 | # ( |
| 71 | # HMETAFILE32 hSrcMetaFile, |
| 72 | # LPCSTR lpFilename |
| 73 | # ); |
Alexandre Julliard | 7cae558 | 2002-06-01 02:55:48 +0000 | [diff] [blame] | 74 | # |
Mike McCormack | e0df32f | 2000-08-11 21:15:21 +0000 | [diff] [blame] | 75 | # PARAMETERS |
| 76 | # HMETAFILE32 hSrcMetaFile |
| 77 | # Handle of metafile to copy. |
Alexandre Julliard | 7cae558 | 2002-06-01 02:55:48 +0000 | [diff] [blame] | 78 | # |
Mike McCormack | e0df32f | 2000-08-11 21:15:21 +0000 | [diff] [blame] | 79 | # LPCSTR lpFilename |
| 80 | # Filename if copying to a file. |
Alexandre Julliard | 7cae558 | 2002-06-01 02:55:48 +0000 | [diff] [blame] | 81 | # |
Mike McCormack | e0df32f | 2000-08-11 21:15:21 +0000 | [diff] [blame] | 82 | # DESCRIPTION |
| 83 | # Copies the metafile corresponding to hSrcMetaFile to |
| 84 | # either a disk file, if a filename is given, or to a new |
| 85 | # memory based metafile, if lpFileName is NULL. |
Alexandre Julliard | 7cae558 | 2002-06-01 02:55:48 +0000 | [diff] [blame] | 86 | # |
Mike McCormack | e0df32f | 2000-08-11 21:15:21 +0000 | [diff] [blame] | 87 | # RETURNS |
| 88 | # Handle to metafile copy on success, NULL on failure. |
Alexandre Julliard | 7cae558 | 2002-06-01 02:55:48 +0000 | [diff] [blame] | 89 | # |
Mike McCormack | e0df32f | 2000-08-11 21:15:21 +0000 | [diff] [blame] | 90 | # BUGS |
| 91 | # Copying to disk returns NULL even if successful. |
Alexandre Julliard | 7cae558 | 2002-06-01 02:55:48 +0000 | [diff] [blame] | 92 | # |
Mike McCormack | e0df32f | 2000-08-11 21:15:21 +0000 | [diff] [blame] | 93 | # SEE ALSO |
| 94 | # GetMetaFileA(3w), GetMetaFileW(3w), CopyMetaFileW(3w), |
| 95 | # PlayMetaFile(3w), SetMetaFileBitsEx(3w), GetMetaFileBit- |
| 96 | # sEx(3w) |
Alexandre Julliard | 7cae558 | 2002-06-01 02:55:48 +0000 | [diff] [blame] | 97 | # |
Mike McCormack | e0df32f | 2000-08-11 21:15:21 +0000 | [diff] [blame] | 98 | ##################################################################################### |
| 99 | |
| 100 | sub output_manpage |
| 101 | { |
| 102 | my ($buffer,$apiref) = @_; |
| 103 | my $parameters; |
| 104 | my $desc; |
| 105 | |
| 106 | # join all the lines of the description together and highlight the headings |
| 107 | for (@$buffer) { |
| 108 | s/\n//g; |
| 109 | s/^\s*//g; |
| 110 | s/\s*$//g; |
| 111 | if ( /^([A-Z]+)$/ ) { |
| 112 | $desc = $desc.".SH $1\n.PP\n"; |
| 113 | } |
| 114 | elsif ( /^$/ ) { |
| 115 | $desc = "$desc\n"; |
| 116 | } |
| 117 | else { |
| 118 | $desc = "$desc $_"; |
| 119 | } |
| 120 | } |
| 121 | |
| 122 | #seperate out all the parameters |
| 123 | |
| 124 | $plist = join ( ' ', @$apiref ); |
| 125 | |
| 126 | $name_type = $plist; |
| 127 | $name_type =~ s/\n//g; # remove newlines |
| 128 | $name_type =~ s/\(.*$//; |
| 129 | $name_type =~ s/WINAPI//; |
| 130 | |
| 131 | #check that this is a function that we want |
| 132 | if ( $funcdb{$apiname."ORD"} eq "" ) { return; } |
| 133 | print "Generating $apiname.$section\n"; |
| 134 | |
| 135 | $plist =~ s/\n//g; # remove newlines |
| 136 | $plist =~ s/^.*\(\s*//; # remove leading bracket and before |
| 137 | $plist =~ s/\s*\).*$//; # remove trailing bracket and leftovers |
| 138 | $plist =~ s/\s*,?\s*\/\*([^*]*)\*\// - $1,/g; # move the comma to the back |
| 139 | @params = split ( /,/ , $plist); # split parameters |
| 140 | for(@params) { |
| 141 | s/^\s*//; |
| 142 | s/\s*$//; |
| 143 | } |
| 144 | |
| 145 | # figure the month and the year |
| 146 | @datetime = localtime; |
| 147 | @months = ( "January", "Febuary", "March", "April", "May", "June", |
| 148 | "July", "August", "September", "October", "November", "December" ); |
| 149 | $date = "$months[$datetime[4]] $datetime[5]"; |
| 150 | |
| 151 | # create the manual page |
| 152 | $manfile = "$mandir/$apiname.$section"; |
| 153 | open(MAN,">$manfile") || die "Couldn't create the man page file $manfile\n"; |
| 154 | print MAN ".\\\" DO NOT MODIFY THIS FILE! It was generated by gendoc 1.0.\n"; |
| 155 | print MAN ".TH $apiname \"$section\" \"$date\" \"Wine API\" \"The Wine Project\"\n"; |
| 156 | print MAN ".SH NAME\n"; |
| 157 | print MAN "$apiname ($apientry)\n"; |
| 158 | print MAN ".SH SYNOPSIS\n"; |
| 159 | print MAN ".PP\n"; |
| 160 | print MAN "$name_type\n"; |
| 161 | print MAN " (\n"; |
Alexandre Julliard | 7cae558 | 2002-06-01 02:55:48 +0000 | [diff] [blame] | 162 | for($i=0; $i<@params; $i++) { |
Mike McCormack | e0df32f | 2000-08-11 21:15:21 +0000 | [diff] [blame] | 163 | $x = ($i == (@params-1)) ? "" : ","; |
| 164 | $c = $params[$i]; |
| 165 | $c =~ s/-.*//; |
| 166 | print MAN " $c$x\n"; |
| 167 | } |
| 168 | print MAN " );\n"; |
| 169 | print MAN ".SH PARAMETERS\n"; |
| 170 | print MAN ".PP\n"; |
Alexandre Julliard | 7cae558 | 2002-06-01 02:55:48 +0000 | [diff] [blame] | 171 | for($i=0; $i<@params; $i++) { |
Mike McCormack | e0df32f | 2000-08-11 21:15:21 +0000 | [diff] [blame] | 172 | print MAN " $params[$i]\n"; |
| 173 | } |
| 174 | print MAN ".SH DESCRIPTION\n"; |
| 175 | print MAN ".PP\n"; |
| 176 | print MAN $desc; |
| 177 | close(MAN); |
| 178 | } |
| 179 | |
| 180 | # |
| 181 | # extract the comments from source file |
| 182 | # |
| 183 | sub parse_source |
| 184 | { |
| 185 | my $file = $_[0]; |
| 186 | print "Processing $file\n"; |
| 187 | |
| 188 | open(SOURCE,"<$file") || die "Couldn't open the source file $file\n"; |
| 189 | $state = 0; |
| 190 | while(<SOURCE>) { |
| 191 | if($state == 0 ) { |
| 192 | if ( /^\/\**$/ ) { |
| 193 | # find the start of the comment /************** |
| 194 | $state = 3; |
| 195 | @buffer = (); |
| 196 | } |
| 197 | } |
| 198 | elsif ($state == 3) { |
| 199 | #extract the wine API name and DLLNAME.XXX string |
Hidenori Takeshima | 4ca46fd | 2000-11-12 03:40:27 +0000 | [diff] [blame] | 200 | if ( / *([A-Za-z_0-9]+) *\(([A-Za-z0-9_]+\.(([0-9]+)|@))\) *$/ ) { |
Mike McCormack | e0df32f | 2000-08-11 21:15:21 +0000 | [diff] [blame] | 201 | $apiname = $1; |
| 202 | $apientry = $2; |
| 203 | $state = 1; |
| 204 | } |
| 205 | else { |
| 206 | $state = 0; |
| 207 | } |
| 208 | } |
| 209 | elsif ($state == 1) { |
| 210 | #save the comment text into buffer, removing leading astericks |
| 211 | if ( /^ \*\// ) { |
| 212 | $state = 2; |
| 213 | } |
| 214 | else { |
| 215 | # find the end of the comment |
| 216 | if ( s/^ \*// ) { |
| 217 | @buffer = ( @buffer , $_ ); |
| 218 | } |
| 219 | else { |
| 220 | $state = 0; |
| 221 | } |
| 222 | } |
| 223 | } |
| 224 | elsif ($state == 2) { |
| 225 | # check that the comment is followed by the declaration of |
| 226 | # a WINAPI function. |
| 227 | if ( /WINAPI/ ) { |
| 228 | @apidef = ( $_ ); |
| 229 | #check if the function's parameters end on this line |
| 230 | if( /\)/ ) { |
| 231 | output_manpage(\@buffer, \@apidef); |
| 232 | $state = 0; |
| 233 | } |
| 234 | else { |
| 235 | $state = 4; |
| 236 | } |
| 237 | } |
| 238 | else { |
| 239 | $state = 0; |
| 240 | } |
| 241 | } |
| 242 | elsif ($state == 4) { |
| 243 | @apidef = ( @apidef , $_ ); |
| 244 | #find the end of the parameters list |
| 245 | if( /\)/ ) { |
| 246 | output_manpage(\@buffer, \@apidef); |
| 247 | $state = 0; |
| 248 | } |
| 249 | } |
| 250 | } |
| 251 | close(SOURCE); |
| 252 | } |
| 253 | |
| 254 | # generate a database of functions to have man pages created from the source |
| 255 | # creates funclist and funcdb |
| 256 | sub parse_spec |
| 257 | { |
| 258 | my $spec = $_[0]; |
| 259 | my $name,$type,$ord,$func; |
| 260 | |
| 261 | open(SPEC,"<$spec") || die "Couldn't open the spec file $spec\n"; |
| 262 | while(<SPEC>) |
| 263 | { |
| 264 | if( /^#/ ) { next; } |
| 265 | if( /^name/ ) { next; } |
| 266 | if( /^type/ ) { next; } |
| 267 | if( /^init/ ) { next; } |
| 268 | if( /^rsrc/ ) { next; } |
| 269 | if( /^import/ ) { next; } |
| 270 | if( /^\s*$/ ) { next; } |
Hidenori Takeshima | 4ca46fd | 2000-11-12 03:40:27 +0000 | [diff] [blame] | 271 | if( /^\s*(([0-9]+)|@)/ ) { |
Mike McCormack | e0df32f | 2000-08-11 21:15:21 +0000 | [diff] [blame] | 272 | s/\(.*\)//; #remove all the args |
| 273 | ($ord,$type,$name,$func) = split( /\s+/ ); |
| 274 | if(( $type eq "stub" ) || ($type eq "forward")) {next;} |
Alexandre Julliard | 7cae558 | 2002-06-01 02:55:48 +0000 | [diff] [blame] | 275 | if( $func eq "" ) { next; } |
Mike McCormack | e0df32f | 2000-08-11 21:15:21 +0000 | [diff] [blame] | 276 | @funclist = ( @funclist , $func ); |
| 277 | $funcdb{$func."ORD"} = $ord; |
| 278 | $funcdb{$func."TYPE"} = $type; |
| 279 | $funcdb{$func."NAME"} = $name; |
| 280 | $funcdb{$func."SPEC"} = $spec; |
| 281 | } |
| 282 | } |
| 283 | close(SPEC); |
| 284 | } |
| 285 | |
| 286 | ###################################################################### |
| 287 | |
| 288 | #main starts here |
| 289 | |
| 290 | $mandir = "man3w"; |
| 291 | $section = "3"; |
| 292 | |
| 293 | #process args |
| 294 | while(@ARGV) { |
| 295 | if($ARGV[0] eq "-o") { # extract output directory |
| 296 | shift @ARGV; |
| 297 | $mandir = $ARGV[0]; |
| 298 | shift @ARGV; |
| 299 | next; |
| 300 | } |
| 301 | if($ARGV[0] =~ s/^-S// ) { # extract man section |
| 302 | $section = $ARGV[0]; |
| 303 | shift @ARGV; |
| 304 | next; |
| 305 | } |
| 306 | if($ARGV[0] =~ s/^-w// ) { # extract man section |
| 307 | shift @ARGV; |
| 308 | @specfiles = ( @specfiles , $ARGV[0] ); |
| 309 | shift @ARGV; |
| 310 | next; |
| 311 | } |
| 312 | if($ARGV[0] =~ s/^-T// ) { |
| 313 | die "FIXME: Only NROFF supported\n"; |
| 314 | } |
| 315 | if($ARGV[0] =~ s/^-[LDiI]// ) { #compatible with C2MAN flags |
| 316 | shift @ARGV; |
| 317 | next; |
| 318 | } |
| 319 | last; # stop after there's no more flags |
| 320 | } |
| 321 | |
| 322 | #print "manual section: $section\n"; |
| 323 | #print "man directory : $mandir\n"; |
| 324 | #print "input files : @ARGV\n"; |
| 325 | #print "spec files : @specfiles\n"; |
| 326 | |
| 327 | while(@specfiles) { |
| 328 | parse_spec($specfiles[0]); |
| 329 | shift @specfiles; |
| 330 | } |
| 331 | |
| 332 | #print "Functions: @funclist\n"; |
| 333 | |
| 334 | while(@ARGV) { |
| 335 | parse_source($ARGV[0]); |
| 336 | shift @ARGV; |
| 337 | } |