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