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