From 5d3f6b0215d301c13b7e4f02a7bc2058b60ffca0 Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Thu, 6 Jan 2022 15:37:05 -0500 Subject: [PATCH] wikiheaders.pl: Added support for export to Unix manpages. This mostly works, but likely needs some tweaking as we examine the output of various pages. Fixes #5163. --- build-scripts/wikiheaders.pl | 279 ++++++++++++++++++++++++++++++++--- 1 file changed, 260 insertions(+), 19 deletions(-) diff --git a/build-scripts/wikiheaders.pl b/build-scripts/wikiheaders.pl index 209a0d5ff..1259087be 100755 --- a/build-scripts/wikiheaders.pl +++ b/build-scripts/wikiheaders.pl @@ -14,6 +14,7 @@ foreach (@ARGV) { $copy_direction = 1, next if $_ eq '--copy-to-headers'; $copy_direction = 1, next if $_ eq '--copy-to-header'; $copy_direction = -1, next if $_ eq '--copy-to-wiki'; + $copy_direction = -2, next if $_ eq '--copy-to-manpages'; $srcpath = $_, next if not defined $srcpath; $wikipath = $_, next if not defined $wikipath; } @@ -199,6 +200,9 @@ sub wikify { } +my $dewikify_mode = 'md'; +my $dewikify_manpage_code_indent = 1; + sub dewikify_chunk { my $wikitype = shift; my $str = shift; @@ -207,30 +211,67 @@ sub dewikify_chunk { #print("\n\nDEWIKIFY CHUNK:\n\n$str\n\n\n"); - if ($wikitype eq 'mediawiki') { - # Doxygen supports Markdown (and it just simply looks better than MediaWiki - # when looking at the raw headers), so do some conversions here as necessary. + if ($dewikify_mode eq 'md') { + if ($wikitype eq 'mediawiki') { + # Doxygen supports Markdown (and it just simply looks better than MediaWiki + # when looking at the raw headers), so do some conversions here as necessary. - $str =~ s/\[\[(SDL_[a-zA-Z0-9_]+)\]\]/$1/gms; # Dump obvious wikilinks. + $str =~ s/\[\[(SDL_[a-zA-Z0-9_]+)\]\]/$1/gms; # Dump obvious wikilinks. - # is also popular. :/ - $str =~ s/\(.*?)<\/code>/`$1`/gms; + # is also popular. :/ + $str =~ s/\(.*?)<\/code>/`$1`/gms; - # bold+italic - $str =~ s/\'''''(.*?)'''''/***$1***/gms; + # bold+italic + $str =~ s/'''''(.*?)'''''/***$1***/gms; - # bold - $str =~ s/\'''(.*?)'''/**$1**/gms; + # bold + $str =~ s/'''(.*?)'''/**$1**/gms; - # italic - $str =~ s/\''(.*?)''/*$1*/gms; + # italic + $str =~ s/''(.*?)''/*$1*/gms; - # bullets - $str =~ s/^\* /- /gm; - } + # bullets + $str =~ s/^\* /- /gm; + } - if (defined $code) { - $str .= "```$codelang$code```"; + if (defined $code) { + $str .= "```$codelang$code```"; + } + } elsif ($dewikify_mode eq 'manpage') { + $str =~ s/\./\\[char46]/gms; # make sure these can't become control codes. + if ($wikitype eq 'mediawiki') { + $str =~ s/\s*\[\[(SDL_[a-zA-Z0-9_]+)\]\]\s*/\n.BR $1\n/gms; # Dump obvious wikilinks. + + # is also popular. :/ + $str =~ s/\s*\(.*?)<\/code>\s*/\n.BR $1\n/gms; + + # bold+italic + $str =~ s/\s*'''''(.*?)'''''\s*/\n.BI $1\n/gms; + + # bold + $str =~ s/\s*'''(.*?)'''\s*/\n.B $1\n/gms; + + # italic + $str =~ s/\s*''(.*?)''\s*/\n.I $1\n/gms; + + # bullets + $str =~ s/^\* /\n\\\(bu /gm; + } else { + die("Unexpected wikitype when converting to manpages\n"); # !!! FIXME: need to handle Markdown wiki pages. + } + + if (defined $code) { + $code =~ s/\A\n+//gms; + $code =~ s/\n+\Z//gms; + if ($dewikify_manpage_code_indent) { + $str .= "\n.IP\n" + } else { + $str .= "\n.PP\n" + } + $str .= ".EX\n$code\n.EE\n.PP\n"; + } + } else { + die("Unexpected dewikify_mode\n"); } #print("\n\nDEWIKIFY CHUNK DONE:\n\n$str\n\n\n"); @@ -260,7 +301,7 @@ sub dewikify { } sub usage { - die("USAGE: $0 [--copy-to-headers|--copy-to-wiki] [--warn-about-missing]\n\n"); + die("USAGE: $0 [--copy-to-headers|--copy-to-wiki|--copy-to-manpages] [--warn-about-missing]\n\n"); } usage() if not defined $srcpath; @@ -551,6 +592,7 @@ if ($warn_about_missing) { if ($copy_direction == 1) { # --copy-to-headers my %changed_headers = (); + $dewikify_mode = 'md'; $wordwrap_mode = 'md'; # the headers use Markdown format. foreach (keys %headerfuncs) { @@ -740,7 +782,7 @@ if ($copy_direction == 1) { # --copy-to-headers my $fn = $_; next if not $headerfuncshasdoxygen{$fn}; my $wikitype = defined $wikitypes{$fn} ? $wikitypes{$fn} : 'mediawiki'; # default to MediaWiki for new stuff FOR NOW. - die("Unexpected wikitype '$wikitype'\n") if (($wikitype ne 'mediawiki') and ($wikitype ne 'md')); + die("Unexpected wikitype '$wikitype'\n") if (($wikitype ne 'mediawiki') and ($wikitype ne 'md') and ($wikitype ne 'manpage')); #print("$fn\n"); next; @@ -1009,6 +1051,205 @@ if ($copy_direction == 1) { # --copy-to-headers close(FH); rename($path, "$wikipath/$_.${wikitype}") or die("Can't rename '$path' to '$wikipath/$_.${wikitype}': $!\n"); } + +} elsif ($copy_direction == -2) { # --copy-to-manpages + # This only takes from the wiki data, since it has sections we omit from the headers, like code examples. + + my $manpath = "$srcpath/man"; + mkdir($manpath); + + $dewikify_mode = 'manpage'; + $wordwrap_mode = 'manpage'; + + my $introtxt = ''; + if (0) { + open(FH, '<', "$srcpath/LICENSE.txt") or die("Can't open '$srcpath/LICENSE.txt': $!\n"); + while () { + chomp; + $introtxt .= ".\\\" $_\n"; + } + close(FH); + } + + my $gitrev = `cd "$srcpath" ; git rev-list HEAD~..`; + chomp($gitrev); + + open(FH, '<', "$srcpath/include/SDL_version.h") or die("Can't open '$srcpath/include/SDL_version.h': $!\n"); + my $majorver = 0; + my $minorver = 0; + my $patchver = 0; + while () { + chomp; + if (/\A\#define SDL_MAJOR_VERSION\s+(\d+)\Z/) { + $majorver = int($1); + } elsif (/\A\#define SDL_MINOR_VERSION\s+(\d+)\Z/) { + $minorver = int($1); + } elsif (/\A\#define SDL_PATCHLEVEL\s+(\d+)\Z/) { + $patchver = int($1); + } + } + close(FH); + my $sdlversion = "$majorver.$minorver.$patchver"; + + foreach (keys %headerfuncs) { + my $fn = $_; + next if not defined $wikifuncs{$fn}; # don't have a page for that function, skip it. + my $wikitype = $wikitypes{$fn}; + my $sectionsref = $wikifuncs{$fn}; + my $remarks = %$sectionsref{'Remarks'}; + my $params = %$sectionsref{'Function Parameters'}; + my $returns = %$sectionsref{'Return Value'}; + my $version = %$sectionsref{'Version'}; + my $related = %$sectionsref{'Related Functions'}; + my $examples = %$sectionsref{'Code Examples'}; + my $deprecated = %$sectionsref{'Deprecated'}; + my $brief = %$sectionsref{'[Brief]'}; + my $decl = $headerdecls{$fn}; + my $str = ''; + + $brief = "$brief"; + $brief =~ s/\A[\s\n]*\= .*? \=\s*?\n+//ms; + $brief =~ s/\A[\s\n]*\=\= .*? \=\=\s*?\n+//ms; + $brief =~ s/\A(.*?\.) /$1\n/; # \brief should only be one sentence, delimited by a period+space. Split if necessary. + my @briefsplit = split /\n/, $brief; + $brief = shift @briefsplit; + $brief = dewikify($wikitype, $brief); + + if (defined $remarks) { + $remarks = dewikify($wikitype, join("\n", @briefsplit) . $remarks); + } + + $str .= $introtxt; + + $str .= ".\\\" This manpage content is licensed under Creative Commons\n"; + $str .= ".\\\" Attribution 4.0 International (CC BY 4.0)\n"; + $str .= ".\\\" https://creativecommons.org/licenses/by/4.0/\n"; + $str .= ".\\\" This manpage was generated from SDL's wiki page for $fn:\n"; + $str .= ".\\\" https://wiki.libsdl.org/$fn\n"; + $str .= ".\\\" Generated with SDL/build-scripts/wikiheaders.pl\n"; + $str .= ".\\\" revision $gitrev\n" if $gitrev ne ''; + $str .= ".\\\" Please report issues in this manpage's content at:\n"; + $str .= ".\\\" https://github.com/libsdl-org/sdlwiki/issues/new?title=Feedback%20on%20page%20$fn\n"; + $str .= ".\\\" Please report issues in the generation of this manpage from the wiki at:\n"; + $str .= ".\\\" https://github.com/libsdl-org/SDL/issues/new?title=Misgenerated%20manpage%20for%20$fn\n"; + $str .= ".\\\" SDL can be found at https://libsdl.org/\n"; + + $str .= ".TH $fn 3 \"SDL $sdlversion\" \"Simple Directmedia Layer\" \"SDL$majorver FUNCTIONS\"\n"; + $str .= ".SH NAME\n"; + + $str .= "$fn"; + $str .= " \\- $brief" if (defined $brief); + $str .= "\n"; + + $str .= ".SH SYNOPSIS\n"; + $str .= ".nf\n"; + $str .= ".B #include \\(dqSDL.h\\(dq\n"; + $str .= ".PP\n"; + + my @decllines = split /\n/, $decl; + foreach (@decllines) { + $str .= ".BI \"$_\n"; + } + $str .= ".fi\n"; + + if (defined $remarks) { + $str .= ".SH DESCRIPTION\n"; + $str .= $remarks . "\n"; + } + + if (defined $deprecated) { + $str .= ".SH DEPRECATED\n"; + $str .= dewikify($wikitype, $deprecated) . "\n"; + } + + if (defined $params) { + $str .= ".SH FUNCTION PARAMETERS\n"; + my @lines = split /\n/, $params; + if ($wikitype eq 'mediawiki') { + die("Unexpected data parsing MediaWiki table") if (shift @lines ne '{|'); # Dump the '{|' start + while (scalar(@lines) >= 3) { + my $name = shift @lines; + my $desc = shift @lines; + my $terminator = shift @lines; # the '|-' or '|}' line. + last if ($terminator ne '|-') and ($terminator ne '|}'); # we seem to have run out of table. + $name =~ s/\A\|\s*//; + $name =~ s/\A\*\*(.*?)\*\*/$1/; + $name =~ s/\A\'\'\'(.*?)\'\'\'/$1/; + $desc =~ s/\A\|\s*//; + $desc = dewikify($wikitype, $desc); + #print STDERR "FN: $fn NAME: $name DESC: $desc TERM: $terminator\n"; + + $str .= ".TP\n"; + $str .= ".I $name\n"; + $str .= "$desc\n"; + } + } else { + die("write me"); + } + } + + if (defined $returns) { + $str .= ".SH RETURN VALUE\n"; + $str .= dewikify($wikitype, $returns) . "\n"; + } + + if (defined $examples) { + $str .= ".SH CODE EXAMPLES\n"; + $dewikify_manpage_code_indent = 0; + $str .= dewikify($wikitype, $examples) . "\n"; + $dewikify_manpage_code_indent = 1; + } + + if (defined $version) { + $str .= ".SH AVAILABILITY\n"; + $str .= dewikify($wikitype, $version) . "\n"; + } + + if (defined $related) { + $str .= ".SH SEE ALSO\n"; + # !!! FIXME: lots of code duplication in all of these. + my $v = dewikify($wikitype, $related); + my @desclines = split /\n/, $v; + my $nextstr = ''; + foreach (@desclines) { + s/\A(\:|\* )//; + s/\(\)\Z//; # Convert "SDL_Func()" to "SDL_Func" + s/\A\.BR\s+//; # dewikify added this, but we want to handle it. + s/\A\s+//; + s/\s+\Z//; + next if $_ eq ''; + $str .= "$nextstr.BR $_ (3)"; + $nextstr = ",\n"; + } + $str .= "\n"; + } + + if (0) { + $str .= ".SH COPYRIGHT\n"; + $str .= "This manpage is licensed under\n"; + $str .= ".UR https://creativecommons.org/licenses/by/4.0/\n"; + $str .= "Creative Commons Attribution 4.0 International (CC BY 4.0)\n"; + $str .= ".UE\n"; + $str .= ".PP\n"; + $str .= "This manpage was generated from\n"; + $str .= ".UR https://wiki.libsdl.org/$fn\n"; + $str .= "SDL's wiki\n"; + $str .= ".UE\n"; + $str .= "using SDL/build-scripts/wikiheaders.pl"; + $str .= " revision $gitrev" if $gitrev ne ''; + $str .= ".\n"; + $str .= "Please report issues in this manpage at\n"; + $str .= ".UR https://github.com/libsdl-org/sdlwiki/issues/new\n"; + $str .= "our bugtracker!\n"; + $str .= ".UE\n"; + } + + my $path = "$manpath/$_.3.tmp"; + open(FH, '>', $path) or die("Can't open '$path': $!\n"); + print FH $str; + close(FH); + rename($path, "$manpath/$_.3") or die("Can't rename '$path' to '$manpath/$_.3': $!\n"); + } } # end of wikiheaders.pl ...