From a390f5716e66a67d4f8f464d5e4c331f18cec521 Mon Sep 17 00:00:00 2001
From: krizej <[EMAIL REDACTED]>
Date: Tue, 8 Apr 2025 20:16:43 +0200
Subject: [PATCH] docs: improve man page generation
---
build-scripts/wikiheaders.pl | 77 +++++++++++++++++++++++++++++-------
1 file changed, 62 insertions(+), 15 deletions(-)
diff --git a/build-scripts/wikiheaders.pl b/build-scripts/wikiheaders.pl
index 98591493b7cc5..019304e9b00d9 100755
--- a/build-scripts/wikiheaders.pl
+++ b/build-scripts/wikiheaders.pl
@@ -424,7 +424,10 @@ sub dewikify_chunk {
$str .= "\n```$codelang\n$code\n```\n";
}
} elsif ($dewikify_mode eq 'manpage') {
- $str =~ s/\./\\[char46]/gms; # make sure these can't become control codes.
+ # make sure these can't become part of roff syntax.
+ $str =~ s/\./\\[char46]/gms;
+ $str =~ s/"/\\(dq/gms;
+
if ($wikitype eq 'mediawiki') {
# Dump obvious wikilinks.
if (defined $apiprefixregex) {
@@ -449,33 +452,52 @@ sub dewikify_chunk {
# bullets
$str =~ s/^\* /\n\\\(bu /gm;
} elsif ($wikitype eq 'md') {
+ # bullets
+ $str =~ s/^\- /\n\\(bu /gm;
+ # merge paragraphs
+ $str =~ s/^[ \t]+//gm;
+ $str =~ s/([^\-\n])\n([^\-\n])/$1 $2/g;
+ $str =~ s/\n\n/\n.PP\n/g;
+
# Dump obvious wikilinks.
if (defined $apiprefixregex) {
- $str =~ s/\[(\`?$apiprefixregex[a-zA-Z0-9_]+\`?)\]\($apiprefixregex[a-zA-Z0-9_]+\)/\n.BR $1\n/gms;
+ my $apr = $apiprefixregex;
+ if(!($apr =~ /\A\(.*\)\Z/s)) {
+ # we're relying on the apiprefixregex having a capturing group.
+ $apr = "(" . $apr . ")";
+ }
+ $str =~ s/(\S*?)\[\`?($apr[a-zA-Z0-9_]+)\`?\]\($apr[a-zA-Z0-9_]+\)(\S*)\s*/\n.BR "" "$1" "$2" "$5"\n/gm;
+ # handle cases like "[x](x), [y](y), [z](z)" being separated.
+ while($str =~ s/(\.BR[^\n]*)\n\n\.BR/$1\n.BR/gm) {}
}
# links
$str =~ s/\[(.*?)]\((https?\:\/\/.*?)\)/\n.URL "$2" "$1"\n/g;
# <code></code> is also popular. :/
- $str =~ s/\s*\`(.*?)\`\s*/\n.BR $1\n/gms;
+ $str =~ s/\s*(\S*?)\`([^\n]*?)\`(\S*)\s*/\n.BR "" "$1" "$2" "$3"\n/gms;
# bold+italic (this looks bad, just make it bold).
- $str =~ s/\s*\*\*\*(.*?)\*\*\*\s*/\n.B $1\n/gms;
+ $str =~ s/\s*(\S*?)\*\*\*([^\n]*?)\*\*\*(\S*)\s*/\n.BR "" "$1" "$2" "$3"\n/gms;
# bold
- $str =~ s/\s*\*\*(.*?)\*\*\s*/\n.B $1\n/gms;
+ $str =~ s/\s*(\S*?)\*\*([^\n]*?)\*\*(\S*)\s*/\n.BR "" "$1" "$2" "$3"\n/gms;
# italic
- $str =~ s/\s*\*(.*?)\*\s*/\n.I $1\n/gms;
-
- # bullets
- $str =~ s/^\- /\n\\\(bu /gm;
+ $str =~ s/\s*(\S*?)\*([^\n]*?)\*(\S*)\s*/\n.IR "" "$1" "$2" "$3"\n/gms;
}
+ # cleanup unnecessary quotes
+ $str =~ s/(\.[IB]R?)(.*?) ""\n/$1$2\n/gm;
+ $str =~ s/(\.[IB]R?) "" ""(.*?)\n/$1$2\n/gm;
+ $str =~ s/"(\S+)"/$1/gm;
+ # cleanup unnecessary whitespace
+ $str =~ s/ +\n/\n/gm;
+
if (defined $code) {
$code =~ s/\A\n+//gms;
$code =~ s/\n+\Z//gms;
+ $code =~ s/\\/\\(rs/gms;
if ($dewikify_manpage_code_indent) {
$str .= "\n.IP\n"
} else {
@@ -580,7 +602,7 @@ sub dewikify {
$retval .= dewikify_chunk($wikitype, $1, $2, $3);
}
} elsif ($wikitype eq 'md') {
- while ($str =~ s/\A(.*?)\n```(.*?)\n(.*?)\n```\n//ms) {
+ while ($str =~ s/\A(.*?)\n?```(.*?)\n(.*?)\n```\n//ms) {
$retval .= dewikify_chunk($wikitype, $1, $2, $3);
}
}
@@ -2765,7 +2787,6 @@ sub generate_quickref {
my $wikitype = $wikitypes{$sym};
my $sectionsref = $wikisyms{$sym};
my $remarks = $sectionsref->{'Remarks'};
- my $params = $sectionsref->{'Function Parameters'};
my $returns = $sectionsref->{'Return Value'};
my $version = $sectionsref->{'Version'};
my $threadsafety = $sectionsref->{'Thread Safety'};
@@ -2773,6 +2794,23 @@ sub generate_quickref {
my $examples = $sectionsref->{'Code Examples'};
my $deprecated = $sectionsref->{'Deprecated'};
my $headerfile = $manpageheaderfiletext;
+
+ my $params = undef;
+
+ if ($symtype == -1) { # category documentation block.
+ # nothing to be done here.
+ } elsif (($symtype == 1) || (($symtype == 5))) { # we'll assume a typedef (5) with a \param is a function pointer typedef.
+ $params = $sectionsref->{'Function Parameters'};
+ } elsif ($symtype == 2) {
+ $params = $sectionsref->{'Macro Parameters'};
+ } elsif ($symtype == 3) {
+ $params = $sectionsref->{'Fields'};
+ } elsif ($symtype == 4) {
+ $params = $sectionsref->{'Values'};
+ } else {
+ die("Unexpected symtype $symtype");
+ }
+
$headerfile =~ s/\%fname\%/$headersymslocation{$sym}/g;
$headerfile .= "\n";
@@ -2839,18 +2877,22 @@ sub generate_quickref {
$str .= dewikify($wikitype, $deprecated) . "\n";
}
+ my $incfile = $mainincludefname;
if (defined $headerfile) {
- $str .= ".SH HEADER FILE\n";
- $str .= dewikify($wikitype, $headerfile) . "\n";
+ if($headerfile =~ /Defined in (.*)/) {
+ $incfile = $1;
+ }
}
$str .= ".SH SYNOPSIS\n";
$str .= ".nf\n";
- $str .= ".B #include \\(dq$mainincludefname\\(dq\n";
+ $str .= ".B #include <$incfile>\n";
$str .= ".PP\n";
my @decllines = split /\n/, $decl;
foreach (@decllines) {
+ $_ =~ s/\\/\\(rs/g; # fix multiline macro defs
+ $_ =~ s/"/\\(dq/g;
$str .= ".BI \"$_\n";
}
$str .= ".fi\n";
@@ -2938,8 +2980,11 @@ sub generate_quickref {
}
if (defined $returns) {
+ # Chop datatype in parentheses off the front.
+ if(!($returns =~ s/\A\([^\[]*\[[^\]]*\]\([^\)]*\)[^\)]*\) //ms)) {
+ $returns =~ s/\A\([^\)]*\) //ms;
+ }
$returns = dewikify($wikitype, $returns);
- $returns =~ s/\A\(.*?\)\s*//; # Chop datatype in parentheses off the front.
$str .= ".SH RETURN VALUE\n";
$str .= "$returns\n";
}
@@ -2975,6 +3020,8 @@ sub generate_quickref {
s/\A\/*//;
s/\A\.BR\s+//; # dewikify added this, but we want to handle it.
s/\A\.I\s+//; # dewikify added this, but we want to handle it.
+ s/\A\.PP\s*//; # dewikify added this, but we want to handle it.
+ s/\\\(bu//; # dewikify added this, but we want to handle it.
s/\A\s*[\:\*\-]\s*//;
s/\A\s+//;
s/\s+\Z//;