blob: 9f5315cdb11c328d2c59dd5dcf59e2cfeeef2e6b [file] [log] [blame]
Mike McCormacke0df32f2000-08-11 21:15:21 +00001#!/usr/bin/perl
2
3#####################################################################################
Alexandre Julliard7cae5582002-06-01 02:55:48 +00004#
Mike McCormacke0df32f2000-08-11 21:15:21 +00005# c2man.pl v0.1 Copyright (C) 2000 Mike McCormack
6#
Alexandre Julliard0799c1a2002-03-09 23:29:33 +00007# Generates Documents from C source code.
Mike McCormacke0df32f2000-08-11 21:15:21 +00008#
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 Julliard0799c1a2002-03-09 23:29:33 +000013# 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 McCormacke0df32f2000-08-11 21:15:21 +000027# 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 Julliard7cae5582002-06-01 02:55:48 +000038#
Mike McCormacke0df32f2000-08-11 21:15:21 +000039# /******************************************************************
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 Julliard7cae5582002-06-01 02:55:48 +000061#
Mike McCormacke0df32f2000-08-11 21:15:21 +000062# CopyMetaFileA(3w) CopyMetaFileA(3w)
Alexandre Julliard7cae5582002-06-01 02:55:48 +000063#
64#
Mike McCormacke0df32f2000-08-11 21:15:21 +000065# NAME
66# CopyMetaFileA - CopyMetaFile32A (GDI32.23)
Alexandre Julliard7cae5582002-06-01 02:55:48 +000067#
Mike McCormacke0df32f2000-08-11 21:15:21 +000068# SYNOPSIS
69# HMETAFILE32 CopyMetaFileA
70# (
71# HMETAFILE32 hSrcMetaFile,
72# LPCSTR lpFilename
73# );
Alexandre Julliard7cae5582002-06-01 02:55:48 +000074#
Mike McCormacke0df32f2000-08-11 21:15:21 +000075# PARAMETERS
76# HMETAFILE32 hSrcMetaFile
77# Handle of metafile to copy.
Alexandre Julliard7cae5582002-06-01 02:55:48 +000078#
Mike McCormacke0df32f2000-08-11 21:15:21 +000079# LPCSTR lpFilename
80# Filename if copying to a file.
Alexandre Julliard7cae5582002-06-01 02:55:48 +000081#
Mike McCormacke0df32f2000-08-11 21:15:21 +000082# 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 Julliard7cae5582002-06-01 02:55:48 +000086#
Mike McCormacke0df32f2000-08-11 21:15:21 +000087# RETURNS
88# Handle to metafile copy on success, NULL on failure.
Alexandre Julliard7cae5582002-06-01 02:55:48 +000089#
Mike McCormacke0df32f2000-08-11 21:15:21 +000090# BUGS
91# Copying to disk returns NULL even if successful.
Alexandre Julliard7cae5582002-06-01 02:55:48 +000092#
Mike McCormacke0df32f2000-08-11 21:15:21 +000093# SEE ALSO
94# GetMetaFileA(3w), GetMetaFileW(3w), CopyMetaFileW(3w),
95# PlayMetaFile(3w), SetMetaFileBitsEx(3w), GetMetaFileBit-
96# sEx(3w)
Alexandre Julliard7cae5582002-06-01 02:55:48 +000097#
Mike McCormacke0df32f2000-08-11 21:15:21 +000098#####################################################################################
99
100sub 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 Julliard7cae5582002-06-01 02:55:48 +0000162 for($i=0; $i<@params; $i++) {
Mike McCormacke0df32f2000-08-11 21:15:21 +0000163 $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 Julliard7cae5582002-06-01 02:55:48 +0000171 for($i=0; $i<@params; $i++) {
Mike McCormacke0df32f2000-08-11 21:15:21 +0000172 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#
183sub 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 Takeshima4ca46fd2000-11-12 03:40:27 +0000200 if ( / *([A-Za-z_0-9]+) *\(([A-Za-z0-9_]+\.(([0-9]+)|@))\) *$/ ) {
Mike McCormacke0df32f2000-08-11 21:15:21 +0000201 $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
256sub 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 Takeshima4ca46fd2000-11-12 03:40:27 +0000271 if( /^\s*(([0-9]+)|@)/ ) {
Mike McCormacke0df32f2000-08-11 21:15:21 +0000272 s/\(.*\)//; #remove all the args
273 ($ord,$type,$name,$func) = split( /\s+/ );
274 if(( $type eq "stub" ) || ($type eq "forward")) {next;}
Alexandre Julliard7cae5582002-06-01 02:55:48 +0000275 if( $func eq "" ) { next; }
Mike McCormacke0df32f2000-08-11 21:15:21 +0000276 @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
294while(@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
327while(@specfiles) {
328 parse_spec($specfiles[0]);
329 shift @specfiles;
330}
331
332#print "Functions: @funclist\n";
333
334while(@ARGV) {
335 parse_source($ARGV[0]);
336 shift @ARGV;
337}