325 lines
9.0 KiB
Perl
325 lines
9.0 KiB
Perl
|
#!/usr/bin/perl
|
||
|
|
||
|
#####################################################################################
|
||
|
#
|
||
|
# c2man.pl v0.1 Copyright (C) 2000 Mike McCormack
|
||
|
#
|
||
|
# Genenerates 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.
|
||
|
#
|
||
|
# 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;
|
||
|
}
|
||
|
|