curl/scripts/managen
Daniel Stenberg a95fd86404
managen: fix the option sort order
... it used to strip off the .d file extension to sort correctly but
ever since the extension changed to .md the operation failed and the
sort got wrong.

Follow-up to 2494b8dd51

Closes #13567
2024-05-09 10:39:43 +02:00

1144 lines
29 KiB
Perl
Executable File

#!/usr/bin/env perl
#***************************************************************************
# _ _ ____ _
# Project ___| | | | _ \| |
# / __| | | | |_) | |
# | (__| |_| | _ <| |___
# \___|\___/|_| \_\_____|
#
# Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
#
# This software is licensed as described in the file COPYING, which
# you should have received as part of this distribution. The terms
# are also available at https://curl.se/docs/copyright.html.
#
# You may opt to use, copy, modify, merge, publish, distribute and/or sell
# copies of the Software, and permit persons to whom the Software is
# furnished to do so, under the terms of the COPYING file.
#
# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
# KIND, either express or implied.
#
# SPDX-License-Identifier: curl
#
###########################################################################
=begin comment
This script generates the manpage.
Example: managen <command> [files] > curl.1
Dev notes:
We open *input* files in :crlf translation (a no-op on many platforms) in
case we have CRLF line endings in Windows but a perl that defaults to LF.
Unfortunately it seems some perls like msysgit cannot handle a global input-only
:crlf so it has to be specified on each file open for text input.
=end comment
=cut
my %optshort;
my %optlong;
my %helplong;
my %arglong;
my %redirlong;
my %protolong;
my %catlong;
use POSIX qw(strftime);
my @ts;
if (defined($ENV{SOURCE_DATE_EPOCH})) {
@ts = gmtime($ENV{SOURCE_DATE_EPOCH});
} else {
@ts = localtime;
}
my $date = strftime "%Y-%m-%d", @ts;
my $year = strftime "%Y", @ts;
my $version = "unknown";
my $globals;
# get the long name version, return the man page string
sub manpageify {
my ($k)=@_;
my $l;
my $trail;
# the matching pattern might include a trailing dot that cannot be part of
# the option name
if($k =~ s/\.$//) {
# cut off trailing dot
$trail = ".";
}
my $klong = $k;
# quote "bare" minuses in the long name
$klong =~ s/-/\\-/g;
if($optlong{$k}) {
# both short + long
$l = "\\fI-".$optlong{$k}.", \\-\\-$klong\\fP$trail";
}
else {
# only long
$l = "\\fI\\-\\-$klong\\fP$trail";
}
return $l;
}
my $colwidth=78; # max number of columns
sub justline {
my ($lvl, @line) = @_;
my $w = -1;
my $spaces = -1;
my $width = $colwidth - ($lvl * 4);
for(@line) {
$w += length($_);
$w++;
$spaces++;
}
my $inject = $width - $w;
my $ratio = 0; # stay at zero if no spaces at all
if($spaces) {
$ratio = $inject / $spaces;
}
my $spare = 0;
print ' ' x ($lvl * 4);
my $prev;
for(@line) {
while($spare >= 0.90) {
print " ";
$spare--;
}
printf "%s%s", $prev?" ":"", $_;
$prev = 1;
$spare += $ratio;
}
print "\n";
}
sub lastline {
my ($lvl, @line) = @_;
print ' ' x ($lvl * 4);
my $prev = 0;
for(@line) {
printf "%s%s", $prev?" ":"", $_;
$prev = 1;
}
print "\n";
}
sub outputpara {
my ($lvl, $f) = @_;
$f =~ s/\n/ /g;
my $w = 0;
my @words = split(/ */, $f);
my $width = $colwidth - ($lvl * 4);
my @line;
for my $e (@words) {
my $l = length($e);
my $spaces = scalar(@line);
if(($w + $l + $spaces) >= $width) {
justline($lvl, @line);
undef @line;
$w = 0;
}
push @line, $e;
$w += $l; # new width
}
if($w) {
lastline($lvl, @line);
print "\n";
}
}
sub printdesc {
my ($manpage, $baselvl, @desc) = @_;
if($manpage) {
for my $d (@desc) {
print $d;
}
}
else {
my $p = -1;
my $para;
for my $l (@desc) {
my $lvl;
if($l !~ /^[\n\r]+/) {
# get the indent level off the string
$l =~ s/^\[([0-9q]*)\]//;
$lvl = $1;
}
if(($p =~ /q/) && ($lvl !~ /q/)) {
# the previous was quoted, this is not
print "\n";
}
if($lvl != $p) {
outputpara($baselvl + $p, $para);
$para = "";
}
if($lvl =~ /q/) {
# quoted, do not right-justify
chomp $l;
lastline($baselvl + $lvl + 1, $l);
}
else {
$para .= $l;
}
$p = $lvl;
}
outputpara($baselvl + $p, $para);
}
}
sub seealso {
my($standalone, $data)=@_;
if($standalone) {
return sprintf
".SH \"SEE ALSO\"\n$data\n";
}
else {
return "See also $data. ";
}
}
sub overrides {
my ($standalone, $data)=@_;
if($standalone) {
return ".SH \"OVERRIDES\"\n$data\n";
}
else {
return $data;
}
}
sub protocols {
my ($manpage, $standalone, $data)=@_;
if($standalone) {
return ".SH \"PROTOCOLS\"\n$data\n";
}
else {
return "($data) " if($manpage);
return "[1]($data) " if(!$manpage);
}
}
sub too_old {
my ($version)=@_;
my $a = 999999;
if($version =~ /^(\d+)\.(\d+)\.(\d+)/) {
$a = $1 * 1000 + $2 * 10 + $3;
}
elsif($version =~ /^(\d+)\.(\d+)/) {
$a = $1 * 1000 + $2 * 10;
}
if($a < 7500) {
# we consider everything before 7.50.0 to be too old to mention
# specific changes for
return 1;
}
return 0;
}
sub added {
my ($standalone, $data)=@_;
if(too_old($data)) {
# do not mention ancient additions
return "";
}
if($standalone) {
return ".SH \"ADDED\"\nAdded in curl version $data\n";
}
else {
return "Added in $data. ";
}
}
sub render {
my ($manpage, $fh, $f, $line) = @_;
my @desc;
my $tablemode = 0;
my $header = 0;
# if $top is TRUE, it means a top-level page and not a command line option
my $top = ($line == 1);
my $quote;
my $level;
$start = 0;
while(<$fh>) {
my $d = $_;
$line++;
if($d =~ /^\.(SH|BR|IP|B)/) {
print STDERR "$f:$line:1:ERROR: nroff instruction in input: \".$1\"\n";
return 4;
}
if(/^ *<!--/) {
# skip comments
next;
}
if((!$start) && ($_ =~ /^[\r\n]*\z/)) {
# skip leading blank lines
next;
}
$start = 1;
if(/^# (.*)/) {
$header = 1;
if($top != 1) {
# ignored for command line options
$blankline++;
next;
}
push @desc, ".SH $1\n" if($manpage);
push @desc, "[0]$1\n" if(!$manpage);
next;
}
elsif(/^###/) {
print STDERR "$f:$line:1:ERROR: ### header is not supported\n";
exit 3;
}
elsif(/^## (.*)/) {
my $word = $1;
# if there are enclosing quotes, remove them first
$word =~ s/[\"\'](.*)[\"\']\z/$1/;
# remove backticks from headers
$words =~ s/\`//g;
# if there is a space, it needs quotes for man page
if(($word =~ / /) && $manpage) {
$word = "\"$word\"";
}
$level = 1;
if($top == 1) {
push @desc, ".IP $word\n" if($manpage);
push @desc, "\n" if(!$manpage);
push @desc, "[1]$word\n" if(!$manpage);
}
else {
if(!$tablemode) {
push @desc, ".RS\n" if($manpage);
$tablemode = 1;
}
push @desc, ".IP $word\n" if($manpage);
push @desc, "\n" if(!$manpage);
push @desc, "[1]$word\n" if(!$manpage);
}
$header = 1;
next;
}
elsif(/^##/) {
if($top == 1) {
print STDERR "$f:$line:1:ERROR: ## empty header top-level mode\n";
exit 3;
}
if($tablemode) {
# end of table
push @desc, ".RE\n.IP\n";
$tablemode = 0;
}
$header = 1;
next;
}
elsif(/^\.(IP|RS|RE)/) {
my ($cmd) = ($1);
print STDERR "$f:$line:1:ERROR: $cmd detected, use ##-style\n";
return 3;
}
elsif(/^[ \t]*\n/) {
# count and ignore blank lines
$blankline++;
next;
}
elsif($d =~ /^ (.*)/) {
my $word = $1;
if(!$quote && $manpage) {
push @desc, ".nf\n";
}
$quote = 1;
$d = "$word\n";
}
elsif($quote && ($d !~ /^ (.*)/)) {
# end of quote
push @desc, ".fi\n" if($manpage);
$quote = 0;
}
$d =~ s/`%DATE`/$date/g;
$d =~ s/`%VERSION`/$version/g;
$d =~ s/`%GLOBALS`/$globals/g;
# convert backticks to double quotes
$d =~ s/\`/\"/g;
if($d =~ /\(Added in ([0-9.]+)\)/i) {
my $ver = $1;
if(too_old($ver)) {
$d =~ s/ *\(Added in $ver\)//gi;
}
}
if(!$quote) {
if($d =~ /^(.*) /) {
printf STDERR "$f:$line:%d:ERROR: 2 spaces detected\n",
length($1);
return 3;
}
elsif($d =~ /[^\\][\<\>]/) {
print STDERR "$f:$line:1:WARN: un-escaped < or > used\n";
return 3;
}
}
# convert backslash-'<' or '> to just the second character
$d =~ s/\\([><])/$1/g;
# convert single backslash to double-backslash
$d =~ s/\\/\\\\/g if($manpage);
if($manpage) {
if(!$quote && $d =~ /--/) {
$d =~ s/--([a-z0-9.-]+)/manpageify($1)/ge;
}
# quote minuses in the output
$d =~ s/([^\\])-/$1\\-/g;
# replace single quotes
$d =~ s/\'/\\(aq/g;
# handle double quotes or periods first on the line
$d =~ s/^([\.\"])/\\&$1/;
# **bold**
$d =~ s/\*\*(\S.*?)\*\*/\\fB$1\\fP/g;
# *italics*
$d =~ s/\*(\S.*?)\*/\\fI$1\\fP/g;
}
else {
# **bold**
$d =~ s/\*\*(\S.*?)\*\*/$1/g;
# *italics*
$d =~ s/\*(\S.*?)\*/$1/g;
}
# trim trailing spaces
$d =~ s/[ \t]+\z//;
push @desc, "\n" if($blankline && !$header);
$blankline = 0;
push @desc, $d if($manpage);
my $qstr = $quote ? "q": "";
push @desc, "[".(1 + $level)."$qstr]$d" if(!$manpage);
$header = 0;
}
if($tablemode) {
# end of table
push @desc, ".RE\n.IP\n" if($manpage);
}
return @desc;
}
sub single {
my ($dir, $manpage, $f, $standalone)=@_;
my $fh;
open($fh, "<:crlf", "$dir/$f") ||
die "could not find $dir/$f";
my $short;
my $long;
my $tags;
my $added;
my $protocols;
my $arg;
my $mutexed;
my $requires;
my $category;
my @seealso;
my $copyright;
my $spdx;
my @examples; # there can be more than one
my $magic; # cmdline special option
my $line;
my $dline;
my $multi;
my $scope;
my $experimental;
my $start;
my $list; # identifies the list, 1 example, 2 see-also
while(<$fh>) {
$line++;
if(/^ *<!--/) {
next;
}
if(!$start) {
if(/^---/) {
$start = 1;
}
next;
}
if(/^Short: *(.)/i) {
$short=$1;
}
elsif(/^Long: *(.*)/i) {
$long=$1;
}
elsif(/^Added: *(.*)/i) {
$added=$1;
}
elsif(/^Tags: *(.*)/i) {
$tags=$1;
}
elsif(/^Arg: *(.*)/i) {
$arg=$1;
}
elsif(/^Magic: *(.*)/i) {
$magic=$1;
}
elsif(/^Mutexed: *(.*)/i) {
$mutexed=$1;
}
elsif(/^Protocols: *(.*)/i) {
$protocols=$1;
}
elsif(/^See-also: +(.+)/i) {
if($seealso) {
print STDERR "ERROR: duplicated See-also in $f\n";
return 1;
}
push @seealso, $1;
}
elsif(/^See-also:/i) {
$list=2;
}
elsif(/^ *- (.*)/i && ($list == 2)) {
push @seealso, $1;
}
elsif(/^Requires: *(.*)/i) {
$requires=$1;
}
elsif(/^Category: *(.*)/i) {
$category=$1;
}
elsif(/^Example: +(.+)/i) {
push @examples, $1;
}
elsif(/^Example:/i) {
# '1' is the example list
$list = 1;
}
elsif(/^ *- (.*)/i && ($list == 1)) {
push @examples, $1;
}
elsif(/^Multi: *(.*)/i) {
$multi=$1;
}
elsif(/^Scope: *(.*)/i) {
$scope=$1;
}
elsif(/^Experimental: yes/i) {
$experimental=1;
}
elsif(/^C: (.*)/i) {
$copyright=$1;
}
elsif(/^SPDX-License-Identifier: (.*)/i) {
$spdx=$1;
}
elsif(/^Help: *(.*)/i) {
;
}
elsif(/^---/) {
$start++;
if(!$long) {
print STDERR "ERROR: no 'Long:' in $f\n";
return 1;
}
if(!$category) {
print STDERR "ERROR: no 'Category:' in $f\n";
return 2;
}
if(!$examples[0]) {
print STDERR "$f:$line:1:ERROR: no 'Example:' present\n";
return 2;
}
if(!$added) {
print STDERR "$f:$line:1:ERROR: no 'Added:' version present\n";
return 2;
}
if(!$seealso[0]) {
print STDERR "$f:$line:1:ERROR: no 'See-also:' field present\n";
return 2;
}
if(!$copyright) {
print STDERR "$f:$line:1:ERROR: no 'C:' field present\n";
return 2;
}
if(!$spdx) {
print STDERR "$f:$line:1:ERROR: no 'SPDX-License-Identifier:' field present\n";
return 2;
}
last;
}
else {
chomp;
print STDERR "$f:$line:1:WARN: unrecognized line in $f, ignoring:\n:'$_';"
}
}
if($start < 2) {
print STDERR "$f:1:1:ERROR: no proper meta-data header\n";
return 2;
}
my @desc = render($manpage, $fh, $f, $line);
close($fh);
if($tablemode) {
# end of table
push @desc, ".RE\n.IP\n";
}
my $opt;
if(defined($short) && $long) {
$opt = "-$short, --$long";
}
elsif($short && !$long) {
$opt = "-$short";
}
elsif($long && !$short) {
$opt = "--$long";
}
if($arg) {
$opt .= " $arg";
}
# quote "bare" minuses in opt
$opt =~ s/-/\\-/g if($manpage);
if($standalone) {
print ".TH curl 1 \"30 Nov 2016\" \"curl 7.52.0\" \"curl manual\"\n";
print ".SH OPTION\n";
print "curl $opt\n";
}
elsif($manpage) {
print ".IP \"$opt\"\n";
}
else {
lastline(1, $opt);
}
my @leading;
if($protocols) {
push @leading, protocols($manpage, $standalone, $protocols);
}
if($standalone) {
print ".SH DESCRIPTION\n";
}
if($experimental) {
push @leading, "**WARNING**: this option is experimental. Do not use in production.\n\n";
}
my $pre = $manpage ? "\n": "[1]";
if($scope) {
if($scope eq "global") {
push @desc, "\n" if(!$manpage);
push @desc, "${pre}This option is global and does not need to be specified for each use of --next.\n";
}
else {
print STDERR "$f:$line:1:ERROR: unrecognized scope: '$scope'\n";
return 2;
}
}
printdesc($manpage, 2, (@leading, @desc));
undef @desc;
my @extra;
if($multi eq "single") {
push @extra, "${pre}If --$long is provided several times, the last set ".
"value is used.\n";
}
elsif($multi eq "append") {
push @extra, "${pre}--$long can be used several times in a command line\n";
}
elsif($multi eq "boolean") {
my $rev = "no-$long";
# for options that start with "no-" the reverse is then without
# the no- prefix
if($long =~ /^no-/) {
$rev = $long;
$rev =~ s/^no-//;
}
my $dashes = $manpage ? "\\-\\-" : "--";
push @extra,
"${pre}Providing --$long multiple times has no extra effect.\n".
"Disable it again with $dashes$rev.\n";
}
elsif($multi eq "mutex") {
push @extra,
"${pre}Providing --$long multiple times has no extra effect.\n";
}
elsif($multi eq "custom") {
; # left for the text to describe
}
else {
print STDERR "$f:$line:1:ERROR: unrecognized Multi: '$multi'\n";
return 2;
}
printdesc($manpage, 2, @extra);
my @foot;
my $mstr;
my $and = 0;
my $num = scalar(@seealso);
if($num > 2) {
# use commas up to this point
$and = $num - 1;
}
my $i = 0;
for my $k (@seealso) {
if(!$helplong{$k}) {
print STDERR "$f:$line:1:WARN: see-also a non-existing option: $k\n";
}
my $l = $manpage ? manpageify($k) : "--$k";
my $sep = " and";
if($and && ($i < $and)) {
$sep = ",";
}
$mstr .= sprintf "%s$l", $mstr?"$sep ":"";
$i++;
}
push @foot, seealso($standalone, $mstr);
if($requires) {
my $l = $manpage ? manpageify($long) : "--$long";
push @foot, "$l requires that the underlying libcurl".
" was built to support $requires. ";
}
if($mutexed) {
my @m=split(/ /, $mutexed);
my $mstr;
for my $k (@m) {
if(!$helplong{$k}) {
print STDERR "WARN: $f mutexes a non-existing option: $k\n";
}
my $l = $manpage ? manpageify($k) : "--$k";
$mstr .= sprintf "%s$l", $mstr?" and ":"";
}
push @foot, overrides($standalone,
"This option is mutually exclusive to $mstr. ");
}
if($examples[0]) {
my $s ="";
$s="s" if($examples[1]);
if($manpage) {
print "\nExample$s:\n";
print ".nf\n";
foreach my $e (@examples) {
$e =~ s!\$URL!https://example.com!g;
# convert single backslahes to doubles
$e =~ s/\\/\\\\/g;
print " curl $e\n";
}
print ".fi\n";
}
else {
my @ex;
push @ex, "[0q]Example$s:\n";
foreach my $e (@examples) {
$e =~ s!\$URL!https://example.com!g;
push @ex, "[0q] curl $e\n";
}
printdesc($manpage, 2, @ex);
}
}
if($added) {
push @foot, added($standalone, $added);
}
if($foot[0]) {
print "\n";
my $f = join("", @foot);
if($manpage) {
$f =~ s/ +\z//; # remove trailing space
print "$f\n";
}
else {
printdesc($manpage, 2, "[1]$f");
}
}
return 0;
}
sub getshortlong {
my ($dir, $f)=@_;
$f =~ s/^.*\///;
open(F, "<:crlf", "$dir/$f") ||
die "could not find $dir/$f";
my $short;
my $long;
my $help;
my $arg;
my $protocols;
my $category;
my $start = 0;
while(<F>) {
if(!$start) {
if(/^---/) {
$start = 1;
}
next;
}
if(/^Short: (.)/i) {
$short=$1;
}
elsif(/^Long: (.*)/i) {
$long=$1;
}
elsif(/^Help: (.*)/i) {
$help=$1;
}
elsif(/^Arg: (.*)/i) {
$arg=$1;
}
elsif(/^Protocols: (.*)/i) {
$protocols=$1;
}
elsif(/^Category: (.*)/i) {
$category=$1;
}
elsif(/^---/) {
last;
}
}
close(F);
if($short) {
$optshort{$short}=$long;
}
if($long) {
$optlong{$long}=$short;
$helplong{$long}=$help;
$arglong{$long}=$arg;
$protolong{$long}=$protocols;
$catlong{$long}=$category;
}
}
sub indexoptions {
my ($dir, @files) = @_;
foreach my $f (@files) {
getshortlong($dir, $f);
}
}
sub header {
my ($dir, $manpage, $f)=@_;
my $fh;
open($fh, "<:crlf", "$dir/$f") ||
die "could not find $dir/$f";
my @d = render($manpage, $fh, $f, 1);
close($fh);
printdesc($manpage, 0, @d);
}
sub listhelp {
print <<HEAD
/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \\| |
* / __| | | | |_) | |
* | (__| |_| | _ <| |___
* \\___|\\___/|_| \\_\\_____|
*
* Copyright (C) Daniel Stenberg, <daniel\@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at https://curl.se/docs/copyright.html.
*
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of the Software, and permit persons to whom the Software is
* furnished to do so, under the terms of the COPYING file.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
* SPDX-License-Identifier: curl
*
***************************************************************************/
#include "tool_setup.h"
#include "tool_help.h"
/*
* DO NOT edit tool_listhelp.c manually.
* This source file is generated with the following command in an autotools
* build:
*
* "make listhelp"
*/
const struct helptxt helptext[] = {
HEAD
;
foreach my $f (sort keys %helplong) {
my $long = $f;
my $short = $optlong{$long};
my @categories = split ' ', $catlong{$long};
my $bitmask = ' ';
my $opt;
if(defined($short) && $long) {
$opt = "-$short, --$long";
}
elsif($long && !$short) {
$opt = " --$long";
}
for my $i (0 .. $#categories) {
$bitmask .= 'CURLHELP_' . uc $categories[$i];
# If not last element, append |
if($i < $#categories) {
$bitmask .= ' | ';
}
}
$bitmask =~ s/(?=.{76}).{1,76}\|/$&\n /g;
my $arg = $arglong{$long};
if($arg) {
$opt .= " $arg";
}
my $desc = $helplong{$f};
$desc =~ s/\"/\\\"/g; # escape double quotes
my $line = sprintf " {\"%s\",\n \"%s\",\n %s},\n", $opt, $desc, $bitmask;
if(length($opt) > 78) {
print STDERR "WARN: the --$long name is too long\n";
}
elsif(length($desc) > 78) {
print STDERR "WARN: the --$long description is too long\n";
}
print $line;
}
print <<FOOT
{ NULL, NULL, CURLHELP_HIDDEN }
};
FOOT
;
}
sub listcats {
my %allcats;
foreach my $f (sort keys %helplong) {
my @categories = split ' ', $catlong{$f};
foreach (@categories) {
$allcats{$_} = undef;
}
}
my @categories;
foreach my $key (keys %allcats) {
push @categories, $key;
}
@categories = sort @categories;
unshift @categories, 'hidden';
for my $i (0..$#categories) {
print '#define ' . 'CURLHELP_' . uc($categories[$i]) . ' ' . "1u << " . $i . "u\n";
}
}
sub listglobals {
my ($dir, @files) = @_;
my @globalopts;
# Find all global options and output them
foreach my $f (sort @files) {
open(F, "<:crlf", "$dir/$f") ||
die "could not read $dir/$f";
my $long;
my $start = 0;
while(<F>) {
if(/^---/) {
if(!$start) {
$start = 1;
next;
}
else {
last;
}
}
if(/^Long: *(.*)/i) {
$long=$1;
}
elsif(/^Scope: global/i) {
push @globalopts, $long;
last;
}
}
close(F);
}
return $ret if($ret);
for my $e (0 .. $#globalopts) {
$globals .= sprintf "%s--%s", $e?($globalopts[$e+1] ? ", " : " and "):"",
$globalopts[$e],;
}
}
sub noext {
my $in = $_[0];
$in =~ s/\.md//;
return $in;
}
sub sortnames {
return noext($a) cmp noext($b);
}
sub mainpage {
my ($dir, $manpage, @files) = @_;
# $manpage is 1 for nroff, 0 for ASCII
my $ret;
my $fh;
open($fh, "<:crlf", "$dir/mainpage.idx") ||
die "no $dir/mainpage.idx file";
print <<HEADER
.\\" **************************************************************************
.\\" * _ _ ____ _
.\\" * Project ___| | | | _ \\| |
.\\" * / __| | | | |_) | |
.\\" * | (__| |_| | _ <| |___
.\\" * \\___|\\___/|_| \\_\\_____|
.\\" *
.\\" * Copyright (C) Daniel Stenberg, <daniel\@haxx.se>, et al.
.\\" *
.\\" * This software is licensed as described in the file COPYING, which
.\\" * you should have received as part of this distribution. The terms
.\\" * are also available at https://curl.se/docs/copyright.html.
.\\" *
.\\" * You may opt to use, copy, modify, merge, publish, distribute and/or sell
.\\" * copies of the Software, and permit persons to whom the Software is
.\\" * furnished to do so, under the terms of the COPYING file.
.\\" *
.\\" * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
.\\" * KIND, either express or implied.
.\\" *
.\\" * SPDX-License-Identifier: curl
.\\" *
.\\" **************************************************************************
.\\"
.\\" DO NOT EDIT. Generated by the curl project managen man page generator.
.\\"
.TH curl 1 "$date" "curl $version" "curl Manual"
HEADER
if ($manpage);
while(<$fh>) {
my $f = $_;
chomp $f;
if($f =~ /^#/) {
# standard comment
next;
}
if(/^%options/) {
# output docs for all options
foreach my $f (sort sortnames @files) {
$ret += single($dir, $manpage, $f, 0);
}
}
else {
# render the file
header($dir, $manpage, $f);
}
}
close($fh);
exit $ret if($ret);
}
sub showonly {
my ($f) = @_;
if(single($f, 1)) {
print STDERR "$f: failed\n";
}
}
sub showprotocols {
my %prots;
foreach my $f (keys %optlong) {
my @p = split(/ /, $protolong{$f});
for my $p (@p) {
$prots{$p}++;
}
}
for(sort keys %prots) {
printf "$_ (%d options)\n", $prots{$_};
}
}
sub getargs {
my ($dir, $f, @s) = @_;
if($f eq "mainpage") {
listglobals($dir, @s);
mainpage($dir, 1, @s);
return;
}
elsif($f eq "ascii") {
listglobals($dir, @s);
mainpage($dir, 0, @s);
return;
}
elsif($f eq "listhelp") {
listhelp();
return;
}
elsif($f eq "single") {
showonly($s[0]);
return;
}
elsif($f eq "protos") {
showprotocols();
return;
}
elsif($f eq "listcats") {
listcats();
return;
}
print "Usage: managen ".
"[-d dir] <mainpage/ascii/listhelp/single FILE/protos/listcats> [files]\n";
}
#------------------------------------------------------------------------
my $dir = ".";
my $include = "../../include";
my $cmd = shift @ARGV;
check:
if($cmd eq "-d") {
# specifies source directory
$dir = shift @ARGV;
$cmd = shift @ARGV;
goto check;
}
elsif($cmd eq "-I") {
# include path root
$include = shift @ARGV;
$cmd = shift @ARGV;
goto check;
}
my @files = @ARGV; # the rest are the files
open(INC, "<$include/curl/curlver.h");
while(<INC>) {
if($_ =~ /^#define LIBCURL_VERSION \"([0-9.]*)/) {
$version = $1;
last;
}
}
close(INC);
# learn all existing options
indexoptions($dir, @files);
getargs($dir, $cmd, @files);