From 8edbe90dd289153acba4948df918f00ecfba54a1 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Sat, 19 Jul 2003 03:08:29 +0000 Subject: [PATCH] Correctly spot forwards. Various improvements and fixes to the output, add index for html. --- tools/c2man.pl | 343 ++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 279 insertions(+), 64 deletions(-) diff --git a/tools/c2man.pl b/tools/c2man.pl index 3c78b9b5814..5798ae2f952 100755 --- a/tools/c2man.pl +++ b/tools/c2man.pl @@ -22,13 +22,20 @@ # TODO # SGML gurus - feel free to smarten up the SGML. # Add any other relevant information for the dll - imports etc -# Read .spec flags such as -i386,-noname and add to docs appropriately -# Generate an alpabetical listing of every API call, with links # Should we have a special output mode for WineHQ? use strict; use bytes; +# Function flags. most of these come from the spec flags +my $FLAG_DOCUMENTED = 1; +my $FLAG_NONAME = 2; +my $FLAG_I386 = 4; +my $FLAG_REGISTER = 8; +my $FLAG_APAIR = 16; # The A version of a matching W function +my $FLAG_WPAIR = 32; # The W version of a matching A function + + # Options my $opt_output_directory = "man3w"; # All default options are for nroff (man pages) my $opt_manual_section = "3w"; @@ -45,13 +52,15 @@ my @opt_source_file_list = (); my %spec_files; # All the collected details about all the source files being processed my %source_files; +# All documented functions that are to be placed in the index +my @index_entries_list = (); # useful globals my $pwd = `pwd`."/"; $pwd =~ s/\n//; my @datetime = localtime; my @months = ( "Jan", "Feb", "Mar", "Apr", "May", "Jun", - "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" ); + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" ); my $year = $datetime[5] + 1900; my $date = "$months[$datetime[4]] $year"; @@ -94,10 +103,12 @@ while(defined($_ = shift @ARGV)) /^e$/ && do { $opt_output_empty = 1; last; }; /^L$/ && do { last; }; /^w$/ && do { @opt_spec_file_list = (@opt_spec_file_list, shift @ARGV); last; }; - s/^I// && do { my $include = $_."/*.h"; - $include =~ s/\/\//\//g; - my $have_headers = `ls $include >/dev/null 2>&1`; - if ($? >> 8 == 0) { @opt_header_file_list = (@opt_header_file_list, $include); } + s/^I// && do { if ($_ ne ".") { + my $include = $_."/*.h"; + $include =~ s/\/\//\//g; + my $have_headers = `ls $include >/dev/null 2>&1`; + if ($? >> 8 == 0) { @opt_header_file_list = (@opt_header_file_list, $include); } + } last; }; s/^R// && do { if ($_ =~ /^\//) { $opt_wine_root_dir = $_; } @@ -216,10 +227,24 @@ sub process_spec_file s/\s+/ /g; # Strip multiple tabs & spaces to a single space s/\s*#.*//; # Strip comments s/\(.*\)/ /; # Strip arguments - s/ \-[a-z0-9]+//g; # Strip modifiers s/\s+/ /g; # Strip multiple tabs & spaces to a single space (again) s/\n$//; # Strip newline + my $flags = 0; + if( /\-noname/ ) + { + $flags |= $FLAG_NONAME; + } + if( /\-i386/ ) + { + $flags |= $FLAG_I386; + } + if( /\-register/ ) + { + $flags |= $FLAG_REGISTER; + } + s/ \-[a-z0-9]+//g; # Strip flags + if( /^(([0-9]+)|@) / ) { # This line contains an exported symbol @@ -254,6 +279,14 @@ sub process_spec_file { $implementation_name = $exported_name; } + + if ($implementation_name =~ /(.*?)\./) + { + $call_convention = "forward"; # Referencing a function from another dll + $spec_details->{NUM_FUNCS}--; + $spec_details->{NUM_FORWARDS}++; + } + # Add indices for the exported and implementation names $spec_details->{EXPORTED_NAMES}{$exported_name} = $spec_details->{NUM_EXPORTS}; if ($implementation_name ne $exported_name) @@ -263,8 +296,7 @@ sub process_spec_file # Add the exported entry $spec_details->{NUM_EXPORTS}++; - my $documented = 0; - my @export = ($ordinal, $call_convention, $exported_name, $implementation_name, $documented); + my @export = ($ordinal, $call_convention, $exported_name, $implementation_name, $flags); push (@{$spec_details->{EXPORTS}},[@export]); } } @@ -515,6 +547,7 @@ sub process_source_file sub process_comment_text { my $comment = shift(@_); + my $i = 0; for (@{$comment->{TEXT}}) { @@ -522,7 +555,7 @@ sub process_comment_text { # Map I/O values. These come in too many formats to standardise now.... s/\[I\]|\[i\]|\[in\]|\[IN\]/\[In\] /g; - s/\[O\]|\[o\]|\[out\]\[OUT\]/\[Out\]/g; + s/\[O\]|\[o\]|\[out\]|\[OUT\]/\[Out\]/g; s/\[I\/O\]|\[I\,O\]|\[i\/o\]|\[in\/out\]|\[IN\/OUT\]/\[In\/Out\]/g; # TRUE/FALSE/NULL are defines, capitilise them s/True|true/TRUE/g; @@ -531,7 +564,7 @@ sub process_comment_text # Preferred capitalisations s/ wine| WINE/ Wine/g; s/ API | api / Api /g; - s/DLL| Dll /dll /g; + s/DLL|Dll/dll /g; s/ URL | url / Url /g; s/WIN16|win16/Win16/g; s/WIN32|win32/Win32/g; @@ -551,11 +584,34 @@ sub process_comment_text s/( |\.)(DOS|dos|msdos)( |\.)/$1MS-DOS\(tm\)$3/g; s/( |\.)(UNIX|Unix|unix)( |\.)/$1Unix\(tm\)$3/g; # Abbreviations - s/( chars)/characters/g; + s/( char )/ character /g; + s/( chars )/ characters /g; s/( info )/ information /g; s/( app )/ application /g; s/( apps )/ applications /g; + s/( exe )/ executable /g; + s/( ptr )/ pointer /g; + s/( obj )/ object /g; + s/( err )/ error /g; + s/( bool )/ boolean /g; + # Punctuation + if ( /\[I|\[O/ && ! /\.$/ ) + { + $_ = $_."."; # Always have a full stop at the end of parameter desc. + } + elsif ($i > 0 && /^[A-Z]*$/ && + !(@{$comment->{TEXT}}[$i-1] =~ /\.$/) && + !(@{$comment->{TEXT}}[$i-1] =~ /\:$/)) + { + + if (!(@{$comment->{TEXT}}[$i-1] =~ /^[A-Z]*$/)) + { + # Paragraphs always end with a full stop + @{$comment->{TEXT}}[$i-1] = @{$comment->{TEXT}}[$i-1]."."; + } + } } + $i++; } } @@ -585,11 +641,11 @@ sub process_comment my $exported_names = $spec_details->{EXPORTED_NAMES}; my $export_index = $exported_names->{$comment->{COMMENT_NAME}}; + my $implementation_names = $spec_details->{IMPLEMENTATION_NAMES}; if (!defined($export_index)) { # Perhaps the comment uses the implementation name? - my $implementation_names = $spec_details->{IMPLEMENTATION_NAMES}; $export_index = $implementation_names->{$comment->{COMMENT_NAME}}; } if (!defined($export_index)) @@ -618,7 +674,7 @@ sub process_comment print "Info: Found alternate name '",$1,"\n"; } my $alt_export = @{$spec_details->{EXPORTS}}[$alt_index]; - @$alt_export[4] |= 1; + @$alt_export[4] |= $FLAG_DOCUMENTED; $spec_details->{NUM_DOCS}++; ${@{$comment->{TEXT}}}[1] = ""; } @@ -647,7 +703,7 @@ sub process_comment # Mark the function as documented $spec_details->{NUM_DOCS}++; - @$export[4] |= 1; + @$export[4] |= $FLAG_DOCUMENTED; # This file is used by the DLL - Make sure we get our contributors right push (@{$spec_details->{SOURCES}},$comment->{FILE}); @@ -722,9 +778,45 @@ sub process_comment { if ( !/^[A-Z]+$/ ) { - if ( /^See ([A-Za-z0-9_]+)\.$/ || /^Unicode version of ([A-Za-z0-9_]+)\.$/) + # Dont reject comments that refer to another doc (e.g. A/W) + if ( /^See ([A-Za-z0-9_]+)\.$/ ) { - # Dont reject comments that refer to their A/W couterpart + if ($comment->{COMMENT_NAME} =~ /W$/ ) + { + # This is probably a Unicode version of an Ascii function. + # Create the Ascii name and see if its been documented + my $ascii_name = $comment->{COMMENT_NAME}; + $ascii_name =~ s/W$/A/; + + my $ascii_export_index = $exported_names->{$ascii_name}; + + if (!defined($ascii_export_index)) + { + $ascii_export_index = $implementation_names->{$ascii_name}; + } + if (!defined($ascii_export_index)) + { + if ($opt_verbose > 2) + { + print "Warning: Function '".$comment->{COMMENT_NAME}."' is not an A/W pair.\n"; + } + } + else + { + my $ascii_export = @{$spec_details->{EXPORTS}}[$ascii_export_index]; + if (@$ascii_export[4] & $FLAG_DOCUMENTED) + { + # Flag these functions as an A/W pair + @$ascii_export[4] |= $FLAG_APAIR; + @$export[4] |= $FLAG_WPAIR; + } + } + } + $found_returns = 1; + } + elsif ( /^Unicode version of ([A-Za-z0-9_]+)\.$/ ) + { + @$export[4] |= $FLAG_WPAIR; # Explicitly marked as W version $found_returns = 1; } $found_description_text = 1; @@ -743,7 +835,7 @@ sub process_comment "description and/or RETURNS section, skipping\n"; } $spec_details->{NUM_DOCS}--; - @$export[4] &= ~1; + @$export[4] &= ~$FLAG_DOCUMENTED; return; } } @@ -767,43 +859,50 @@ sub process_comment # Find header file my $h_file = ""; - if ($comment->{COMMENT_NAME} ne "") + if (@$export[4] & $FLAG_NONAME) { - my $tmp = "grep -s -l $comment->{COMMENT_NAME} @opt_header_file_list 2>/dev/null"; - $tmp = `$tmp`; - my $exit_value = $? >> 8; - if ($exit_value == 0) - { - $tmp =~ s/\n.*//g; - if ($tmp ne "") - { - $h_file = `basename $tmp`; - } - } - } - elsif ($comment->{ALT_NAME} ne "") - { - my $tmp = "grep -s -l $comment->{ALT_NAME} @opt_header_file_list"." 2>/dev/null"; - $tmp = `$tmp`; - my $exit_value = $? >> 8; - if ($exit_value == 0) - { - $tmp =~ s/\n.*//g; - if ($tmp ne "") - { - $h_file = `basename $tmp`; - } - } - } - $h_file =~ s/^ *//; - $h_file =~ s/\n//; - if ($h_file eq "") - { - $h_file = "Not defined in a Wine header"; + $h_file = "Exported by ordinal only. Use GetProcAddress() to obtain a pointer to the function."; } else { - $h_file = "Defined in \"".$h_file."\""; + if ($comment->{COMMENT_NAME} ne "") + { + my $tmp = "grep -s -l $comment->{COMMENT_NAME} @opt_header_file_list 2>/dev/null"; + $tmp = `$tmp`; + my $exit_value = $? >> 8; + if ($exit_value == 0) + { + $tmp =~ s/\n.*//g; + if ($tmp ne "") + { + $h_file = `basename $tmp`; + } + } + } + elsif ($comment->{ALT_NAME} ne "") + { + my $tmp = "grep -s -l $comment->{ALT_NAME} @opt_header_file_list"." 2>/dev/null"; + $tmp = `$tmp`; + my $exit_value = $? >> 8; + if ($exit_value == 0) + { + $tmp =~ s/\n.*//g; + if ($tmp ne "") + { + $h_file = `basename $tmp`; + } + } + } + $h_file =~ s/^ *//; + $h_file =~ s/\n//; + if ($h_file eq "") + { + $h_file = "Not defined in a Wine header. The function is either undocumented, or missing from Wine." + } + else + { + $h_file = "Defined in \"".$h_file."\"."; + } } # Find source file @@ -822,15 +921,24 @@ sub process_comment $cfile =~ s/^\/+//; # Strip initial directory slash $c_file = $cfile; } - $c_file = "Implemented in \"".$c_file."\""; + $c_file = "Implemented in \"".$c_file."\"."; # Add the implementation details push (@{$comment->{TEXT}}, "IMPLEMENTATION","",$h_file,"",$c_file); + if (@$export[4] & $FLAG_I386) + { + push (@{$comment->{TEXT}}, "", "Available on x86 platforms only."); + } + if (@$export[4] & $FLAG_REGISTER) + { + push (@{$comment->{TEXT}}, "", "This function passes one or more arguments in registers. ", + "For more details, please read the source code."); + } my $source_details = $source_files{$comment->{FILE}}[0]; if ($source_details->{DEBUG_CHANNEL} ne "") { - push (@{$comment->{TEXT}}, "", "Debug channel \"".$source_details->{DEBUG_CHANNEL}."\""); + push (@{$comment->{TEXT}}, "", "Debug channel \"".$source_details->{DEBUG_CHANNEL}."\"."); } # Write out the documentation for the API @@ -1113,7 +1221,7 @@ sub output_spec { my $line = ""; - # @$_ => ordinal, call convention, exported name, implementation name, documented; + # @$_ => ordinal, call convention, exported name, implementation name, flags; if (@$_[1] eq "forward") { my $forward_dll = @$_[3]; @@ -1131,6 +1239,11 @@ sub output_spec elsif (@$_[1] eq "fake") { # Don't add this function here, it gets listed with the extra documentation + if (!(@$_[4] & $FLAG_WPAIR)) + { + # This function should be indexed + push (@index_entries_list, @$_[3].",".@$_[3]); + } } elsif (@$_[1] eq "equate" || @$_[1] eq "variable") { @@ -1139,7 +1252,7 @@ sub output_spec else { # A function - if (@$_[4] & 1) + if (@$_[4] & $FLAG_DOCUMENTED) { # Documented $line = @$_[2]." (implemented as ".@$_[3]."())"; @@ -1151,6 +1264,11 @@ sub output_spec { $line = @$_[2]."()"; } + if (!(@$_[4] & $FLAG_WPAIR)) + { + # This function should be indexed + push (@index_entries_list, @$_[2].",".@$_[3]); + } } else { @@ -1175,6 +1293,9 @@ sub output_spec } } } + # The dll entry should also be indexed + push (@index_entries_list, $spec_details->{DLL_NAME}.",".$spec_details->{DLL_NAME}); + # Write out the document output_open_api_file($spec_details->{DLL_NAME}); output_api_header($comment); @@ -1265,8 +1386,9 @@ sub output_api_footer if ($opt_output_format eq "h") { print OUTPUT "

Copyright © ".$year." The Wine Project.". - "Visit WineHQ for license details.". - "Generated $date

\n\n\n"; + " All trademarks are the property of their respective owners.". + " Visit WineHQ for license details.". + " Generated $date.

\n\n\n"; } elsif ($opt_output_format eq "s") { @@ -1511,6 +1633,9 @@ sub output_api_comment { # Html uses links for API calls s/([A-Za-z_]+[A-Za-z_0-9]+)(\(\))/$1<\/a>/g; + # Index references + s/\{\{(.*?)\}\}\{\{(.*?)\}\}/$1<\/a>/g; + s/ ([A-Z_])(\(\))/$1<\/a>/g; # And references to COM objects (hey, they'll get documented one day) s/ (I[A-Z]{1}[A-Za-z0-9_]+) (Object|object|Interface|interface)/ $1<\/a> $2/g; # Convert any web addresses to real links @@ -1589,7 +1714,7 @@ sub output_api_comment print OUTPUT $fmt[17]; $open_paragraph = 0; } - s/(\[.+\])( *)/$fmt[19]$fmt[10]$1$fmt[11]$fmt[19]/; # Format In/Out + s/(\[.+\])( *)/$fmt[19]$fmt[10]$1$fmt[11]$fmt[19] /; # Format In/Out } else { @@ -1600,8 +1725,11 @@ sub output_api_comment # Format parameter names where they appear in the comment for my $parameter_name (@parameter_names) { - s/(^|[ \.\,\(\-])($parameter_name)($|[ \.\)\,\-])/$1$fmt[8]$2$fmt[9]$3/g; + s/(^|[ \.\,\(\-\*])($parameter_name)($|[ \.\)\,\-\=\/])/$1$fmt[8]$2$fmt[9]$3/g; } + # Structure dereferences include the dereferenced member + s/(\-\>[A-Za-z_]+)/$fmt[8]$1$fmt[9]/g; + s/(\-\>\;[A-Za-z_]+)/$fmt[8]$1$fmt[9]/g; if ($open_paragraph == 0) { @@ -1640,6 +1768,19 @@ sub output_master_index_files return; # No master index for man pages } + if ($opt_output_format eq "h") + { + # Append the index entries to the output db of index entries + my $output_file = $opt_output_directory."/index.db"; + open(INDEXDB,">>$output_file") || die "Couldn't create $output_file\n"; + for (@index_entries_list) + { + $_ =~ s/A\,/\,/; + print INDEXDB $_."\n"; + } + close(INDEXDB); + } + # Use the comment output functions for consistency my $comment = { @@ -1690,10 +1831,16 @@ sub output_master_index_files if ($opt_output_format eq "h") { - # HTML gets a list of all the dlls. For docbook the index creates this for us + # HTML gets a list of all the dlls and an index. For docbook the index creates this for us push (@{$comment->{TEXT}}, + "INDEX", + "For an alphabetical listing of the functions available, please click the ", + "first letter of the functions name below:","", + "[ _(), A(), B(), C(), D(), E(), F(), G(), H(), ". + "I(), J(), K(), L(), M(), N(), O(), P(), Q() ". + "R(), S(), T(), U(), V(), W(), X(), Y(), Z() ]", "", "DLLS", - "The following dlls are provided by Wine:", + "Each dll provided by Wine is documented individually. The following dlls are provided :", "" ); # Add the dlls to the comment @@ -1728,8 +1875,8 @@ sub output_master_index_files } if ($opt_output_format eq "h") { + output_html_index_files(); output_html_stylesheet(); - # FIXME: Create an alphabetical index return; } } @@ -1807,6 +1954,69 @@ sub output_sgml_dll_file `mv $tmp_name $opt_output_directory/$spec_details->{DLL_NAME}.sgml`; } +# Write the html index files containing the function names +sub output_html_index_files +{ + if ($opt_output_format ne "h") + { + return; + } + + my @letters = ('_', 'A' .. 'Z'); + + # Read in all functions + my $input_file = $opt_output_directory."/index.db"; + my @funcs = `cat $input_file|sort|uniq`; + + for (@letters) + { + my $letter = $_; + my $comment = + { + FILE => "", + COMMENT_NAME => "", + ALT_NAME => "", + DLL_NAME => "", + ORDINAL => "", + RETURNS => "", + PROTOTYPE => [], + TEXT => [], + }; + + $comment->{COMMENT_NAME} = $letter." Functions"; + $comment->{ALT_NAME} = $letter." Functions"; + + push (@{$comment->{TEXT}}, + "NAME", + $comment->{COMMENT_NAME}, + "FUNCTIONS" + ); + + # Add the functions to the comment + for (@funcs) + { + my $first_char = substr ($_, 0, 1); + $first_char = uc $first_char; + + if ($first_char eq $letter) + { + my $name = $_; + my $file; + $name =~ s/(^.*?)\,(.*?)\n/$1/; + $file = $2; + push (@{$comment->{TEXT}}, "{{".$name."}}{{".$file."}}",""); + } + } + + # Write out the document + output_open_api_file($letter); + output_api_header($comment); + output_api_comment($comment); + output_api_footer($comment); + output_close_api_file(); + } +} + # Output the stylesheet for HTML output sub output_html_stylesheet { @@ -1825,7 +2035,7 @@ sub output_html_stylesheet BODY { /* Page body */ background-color: white; color: black; -font-family: Tahomsans-serif; +font-family: Tahoma,sans-serif; font-style: normal; font-size: 10pt; } @@ -1868,6 +2078,11 @@ vertical-align: top; margin-left: 0.5in; margin-right: 1.0in; } +pre.raw { /* Raw text output */ +margin-left: 0.6in; +margin-right: 1.1in; +background-color: #8080DC; +} tt.param { /* Parameter name */ font-style: italic; color: blue;