1#!/usr/bin/env perl 2#*************************************************************************** 3# _ _ ____ _ 4# Project ___| | | | _ \| | 5# / __| | | | |_) | | 6# | (__| |_| | _ <| |___ 7# \___|\___/|_| \_\_____| 8# 9# Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al. 10# 11# This software is licensed as described in the file COPYING, which 12# you should have received as part of this distribution. The terms 13# are also available at https://curl.se/docs/copyright.html. 14# 15# You may opt to use, copy, modify, merge, publish, distribute and/or sell 16# copies of the Software, and permit persons to whom the Software is 17# furnished to do so, under the terms of the COPYING file. 18# 19# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 20# KIND, either express or implied. 21# 22# SPDX-License-Identifier: curl 23# 24########################################################################### 25 26=begin comment 27 28This script generates the manpage. 29 30Example: gen.pl <command> [files] > curl.1 31 32Dev notes: 33 34We open *input* files in :crlf translation (a no-op on many platforms) in 35case we have CRLF line endings in Windows but a perl that defaults to LF. 36Unfortunately it seems some perls like msysgit cannot handle a global input-only 37:crlf so it has to be specified on each file open for text input. 38 39=end comment 40=cut 41 42my %optshort; 43my %optlong; 44my %helplong; 45my %arglong; 46my %redirlong; 47my %protolong; 48my %catlong; 49 50use POSIX qw(strftime); 51my @ts; 52if (defined($ENV{SOURCE_DATE_EPOCH})) { 53 @ts = localtime($ENV{SOURCE_DATE_EPOCH}); 54} else { 55 @ts = localtime; 56} 57my $date = strftime "%B %d %Y", @ts; 58my $year = strftime "%Y", @ts; 59my $version = "unknown"; 60my $globals; 61 62open(INC, "<../../include/curl/curlver.h"); 63while(<INC>) { 64 if($_ =~ /^#define LIBCURL_VERSION \"([0-9.]*)/) { 65 $version = $1; 66 last; 67 } 68} 69close(INC); 70 71# get the long name version, return the man page string 72sub manpageify { 73 my ($k)=@_; 74 my $l; 75 my $klong = $k; 76 # quote "bare" minuses in the long name 77 $klong =~ s/-/\\-/g; 78 if($optlong{$k} ne "") { 79 # both short + long 80 $l = "\\fI-".$optlong{$k}.", \\-\\-$klong\\fP"; 81 } 82 else { 83 # only long 84 $l = "\\fI\\-\\-$klong\\fP"; 85 } 86 return $l; 87} 88 89sub printdesc { 90 my @desc = @_; 91 my $exam = 0; 92 for my $d (@desc) { 93 print $d; 94 } 95} 96 97sub seealso { 98 my($standalone, $data)=@_; 99 if($standalone) { 100 return sprintf 101 ".SH \"SEE ALSO\"\n$data\n"; 102 } 103 else { 104 return "See also $data. "; 105 } 106} 107 108sub overrides { 109 my ($standalone, $data)=@_; 110 if($standalone) { 111 return ".SH \"OVERRIDES\"\n$data\n"; 112 } 113 else { 114 return $data; 115 } 116} 117 118sub protocols { 119 my ($standalone, $data)=@_; 120 if($standalone) { 121 return ".SH \"PROTOCOLS\"\n$data\n"; 122 } 123 else { 124 return "($data) "; 125 } 126} 127 128sub too_old { 129 my ($version)=@_; 130 my $a = 999999; 131 if($version =~ /^(\d+)\.(\d+)\.(\d+)/) { 132 $a = $1 * 1000 + $2 * 10 + $3; 133 } 134 elsif($version =~ /^(\d+)\.(\d+)/) { 135 $a = $1 * 1000 + $2 * 10; 136 } 137 if($a < 7500) { 138 # we consider everything before 7.50.0 to be too old to mention 139 # specific changes for 140 return 1; 141 } 142 return 0; 143} 144 145sub added { 146 my ($standalone, $data)=@_; 147 if(too_old($data)) { 148 # do not mention ancient additions 149 return ""; 150 } 151 if($standalone) { 152 return ".SH \"ADDED\"\nAdded in curl version $data\n"; 153 } 154 else { 155 return "Added in $data. "; 156 } 157} 158 159sub render { 160 my ($fh, $f, $line) = @_; 161 my @desc; 162 my $tablemode = 0; 163 my $header = 0; 164 # if $top is TRUE, it means a top-level page and not a command line option 165 my $top = ($line == 1); 166 my $quote; 167 $start = 0; 168 169 while(<$fh>) { 170 my $d = $_; 171 $line++; 172 if($d =~ /^\.(SH|BR|IP|B)/) { 173 print STDERR "$f:$line:1:ERROR: nroff instruction in input: \".$1\"\n"; 174 return 4; 175 } 176 if(/^ *<!--/) { 177 # skip comments 178 next; 179 } 180 if((!$start) && ($_ =~ /^[\r\n]*\z/)) { 181 # skip leading blank lines 182 next; 183 } 184 $start = 1; 185 if(/^# (.*)/) { 186 $header = 1; 187 if($top != 1) { 188 # ignored for command line options 189 $blankline++; 190 next; 191 } 192 push @desc, ".SH $1\n"; 193 next; 194 } 195 elsif(/^###/) { 196 print STDERR "$f:$line:1:ERROR: ### header is not supported\n"; 197 exit 3; 198 } 199 elsif(/^## (.*)/) { 200 my $word = $1; 201 # if there are enclosing quotes, remove them first 202 $word =~ s/[\"\'](.*)[\"\']\z/$1/; 203 204 # remove backticks from headers 205 $words =~ s/\`//g; 206 207 # if there is a space, it needs quotes 208 if($word =~ / /) { 209 $word = "\"$word\""; 210 } 211 if($top == 1) { 212 push @desc, ".IP $word\n"; 213 } 214 else { 215 if(!$tablemode) { 216 push @desc, ".RS\n"; 217 $tablemode = 1; 218 } 219 push @desc, ".IP $word\n"; 220 } 221 $header = 1; 222 next; 223 } 224 elsif(/^##/) { 225 if($top == 1) { 226 print STDERR "$f:$line:1:ERROR: ## empty header top-level mode\n"; 227 exit 3; 228 } 229 if($tablemode) { 230 # end of table 231 push @desc, ".RE\n.IP\n"; 232 $tablmode = 0; 233 } 234 $header = 1; 235 next; 236 } 237 elsif(/^\.(IP|RS|RE)/) { 238 my ($cmd) = ($1); 239 print STDERR "$f:$line:1:ERROR: $cmd detected, use ##-style\n"; 240 return 3; 241 } 242 elsif(/^[ \t]*\n/) { 243 # count and ignore blank lines 244 $blankline++; 245 next; 246 } 247 elsif($d =~ /^ (.*)/) { 248 my $word = $1; 249 if(!$quote) { 250 push @desc, ".nf\n"; 251 } 252 $quote = 1; 253 $d = "$word\n"; 254 } 255 elsif($quote && ($d !~ /^ (.*)/)) { 256 # end of quote 257 push @desc, ".fi\n"; 258 $quote = 0; 259 } 260 261 $d =~ s/`%DATE`/$date/g; 262 $d =~ s/`%VERSION`/$version/g; 263 $d =~ s/`%GLOBALS`/$globals/g; 264 265 # convert single backslahes to doubles 266 $d =~ s/\\/\\\\/g; 267 268 # convert backticks to double quotes 269 $d =~ s/\`/\"/g; 270 271 if(!$quote && $d =~ /--/) { 272 # scan for options in longest-names first order 273 for my $k (sort {length($b) <=> length($a)} keys %optlong) { 274 # --tlsv1 is complicated since --tlsv1.2 etc are also 275 # acceptable options! 276 if(($k eq "tlsv1") && ($d =~ /--tlsv1\.[0-9]\\f/)) { 277 next; 278 } 279 my $l = manpageify($k); 280 $d =~ s/\-\-$k([^a-z0-9-])/$l$1/g; 281 } 282 } 283 284 if($d =~ /\(Added in ([0-9.]+)\)/i) { 285 my $ver = $1; 286 if(too_old($ver)) { 287 $d =~ s/ *\(Added in $ver\)//gi; 288 } 289 } 290 291 if(!$quote && ($d =~ /^(.*) /)) { 292 printf STDERR "$f:$line:%d:ERROR: 2 spaces detected\n", 293 length($1); 294 return 3; 295 } 296 # quote minuses in the output 297 $d =~ s/([^\\])-/$1\\-/g; 298 # replace single quotes 299 $d =~ s/\'/\\(aq/g; 300 # handle double quotes or periods first on the line 301 $d =~ s/^([\.\"])/\\&$1/; 302 # **bold** 303 $d =~ s/\*\*(\S.*?)\*\*/\\fB$1\\fP/g; 304 # *italics* 305 $d =~ s/\*(\S.*?)\*/\\fI$1\\fP/g; 306 307 # trim trailing spaces 308 $d =~ s/[ \t]+\z//; 309 push @desc, "\n" if($blankline && !$header); 310 $blankline = 0; 311 push @desc, $d; 312 $header = 0; 313 314 } 315 if($tablemode) { 316 # end of table 317 push @desc, ".RE\n.IP\n"; 318 } 319 return @desc; 320} 321 322sub single { 323 my ($f, $standalone)=@_; 324 my $fh; 325 open($fh, "<:crlf", "$f") || 326 return 1; 327 my $short; 328 my $long; 329 my $tags; 330 my $added; 331 my $protocols; 332 my $arg; 333 my $mutexed; 334 my $requires; 335 my $category; 336 my @seealso; 337 my $copyright; 338 my $spdx; 339 my @examples; # there can be more than one 340 my $magic; # cmdline special option 341 my $line; 342 my $dline; 343 my $multi; 344 my $scope; 345 my $experimental; 346 my $start; 347 my $list; # identifies the list, 1 example, 2 see-also 348 while(<$fh>) { 349 $line++; 350 if(/^ *<!--/) { 351 next; 352 } 353 if(!$start) { 354 if(/^---/) { 355 $start = 1; 356 } 357 next; 358 } 359 if(/^Short: *(.)/i) { 360 $short=$1; 361 } 362 elsif(/^Long: *(.*)/i) { 363 $long=$1; 364 } 365 elsif(/^Added: *(.*)/i) { 366 $added=$1; 367 } 368 elsif(/^Tags: *(.*)/i) { 369 $tags=$1; 370 } 371 elsif(/^Arg: *(.*)/i) { 372 $arg=$1; 373 } 374 elsif(/^Magic: *(.*)/i) { 375 $magic=$1; 376 } 377 elsif(/^Mutexed: *(.*)/i) { 378 $mutexed=$1; 379 } 380 elsif(/^Protocols: *(.*)/i) { 381 $protocols=$1; 382 } 383 elsif(/^See-also: +(.+)/i) { 384 if($seealso) { 385 print STDERR "ERROR: duplicated See-also in $f\n"; 386 return 1; 387 } 388 push @seealso, $1; 389 } 390 elsif(/^See-also:/i) { 391 $list=2; 392 } 393 elsif(/^ *- (.*)/i && ($list == 2)) { 394 push @seealso, $1; 395 } 396 elsif(/^Requires: *(.*)/i) { 397 $requires=$1; 398 } 399 elsif(/^Category: *(.*)/i) { 400 $category=$1; 401 } 402 elsif(/^Example: +(.+)/i) { 403 push @examples, $1; 404 } 405 elsif(/^Example:/i) { 406 # '1' is the example list 407 $list = 1; 408 } 409 elsif(/^ *- (.*)/i && ($list == 1)) { 410 push @examples, $1; 411 } 412 elsif(/^Multi: *(.*)/i) { 413 $multi=$1; 414 } 415 elsif(/^Scope: *(.*)/i) { 416 $scope=$1; 417 } 418 elsif(/^Experimental: yes/i) { 419 $experimental=1; 420 } 421 elsif(/^C: (.*)/i) { 422 $copyright=$1; 423 } 424 elsif(/^SPDX-License-Identifier: (.*)/i) { 425 $spdx=$1; 426 } 427 elsif(/^Help: *(.*)/i) { 428 ; 429 } 430 elsif(/^---/) { 431 $start++; 432 if(!$long) { 433 print STDERR "ERROR: no 'Long:' in $f\n"; 434 return 1; 435 } 436 if(!$category) { 437 print STDERR "ERROR: no 'Category:' in $f\n"; 438 return 2; 439 } 440 if(!$examples[0]) { 441 print STDERR "$f:$line:1:ERROR: no 'Example:' present\n"; 442 return 2; 443 } 444 if(!$added) { 445 print STDERR "$f:$line:1:ERROR: no 'Added:' version present\n"; 446 return 2; 447 } 448 if(!$seealso[0]) { 449 print STDERR "$f:$line:1:ERROR: no 'See-also:' field present\n"; 450 return 2; 451 } 452 if(!$copyright) { 453 print STDERR "$f:$line:1:ERROR: no 'C:' field present\n"; 454 return 2; 455 } 456 if(!$spdx) { 457 print STDERR "$f:$line:1:ERROR: no 'SPDX-License-Identifier:' field present\n"; 458 return 2; 459 } 460 last; 461 } 462 else { 463 chomp; 464 print STDERR "$f:$line:1:WARN: unrecognized line in $f, ignoring:\n:'$_';" 465 } 466 } 467 468 if($start < 2) { 469 print STDERR "$f:1:1:ERROR: no proper meta-data header\n"; 470 return 2; 471 } 472 473 my @desc = render($fh, $f, $line); 474 close($fh); 475 if($tablemode) { 476 # end of table 477 push @desc, ".RE\n.IP\n"; 478 } 479 my $opt; 480 481 if(defined($short) && $long) { 482 $opt = "-$short, --$long"; 483 } 484 elsif($short && !$long) { 485 $opt = "-$short"; 486 } 487 elsif($long && !$short) { 488 $opt = "--$long"; 489 } 490 491 if($arg) { 492 $opt .= " $arg"; 493 } 494 495 # quote "bare" minuses in opt 496 $opt =~ s/-/\\-/g; 497 if($standalone) { 498 print ".TH curl 1 \"30 Nov 2016\" \"curl 7.52.0\" \"curl manual\"\n"; 499 print ".SH OPTION\n"; 500 print "curl $opt\n"; 501 } 502 else { 503 print ".IP \"$opt\"\n"; 504 } 505 if($protocols) { 506 print protocols($standalone, $protocols); 507 } 508 509 if($standalone) { 510 print ".SH DESCRIPTION\n"; 511 } 512 513 if($experimental) { 514 print "**WARNING**: this option is experimental. Do not use in production.\n\n"; 515 } 516 517 printdesc(@desc); 518 undef @desc; 519 520 if($scope) { 521 if($scope eq "global") { 522 print "\nThis option is global and does not need to be specified for each use of --next.\n"; 523 } 524 else { 525 print STDERR "$f:$line:1:ERROR: unrecognized scope: '$scope'\n"; 526 return 2; 527 } 528 } 529 530 my @extra; 531 if($multi eq "single") { 532 push @extra, "\nIf --$long is provided several times, the last set ". 533 "value is used.\n"; 534 } 535 elsif($multi eq "append") { 536 push @extra, "\n--$long can be used several times in a command line\n"; 537 } 538 elsif($multi eq "boolean") { 539 my $rev = "no-$long"; 540 # for options that start with "no-" the reverse is then without 541 # the no- prefix 542 if($long =~ /^no-/) { 543 $rev = $long; 544 $rev =~ s/^no-//; 545 } 546 push @extra, 547 "\nProviding --$long multiple times has no extra effect.\n". 548 "Disable it again with \\-\\-$rev.\n"; 549 } 550 elsif($multi eq "mutex") { 551 push @extra, 552 "\nProviding --$long multiple times has no extra effect.\n"; 553 } 554 elsif($multi eq "custom") { 555 ; # left for the text to describe 556 } 557 else { 558 print STDERR "$f:$line:1:ERROR: unrecognized Multi: '$multi'\n"; 559 return 2; 560 } 561 562 printdesc(@extra); 563 564 my @foot; 565 566 my $mstr; 567 my $and = 0; 568 my $num = scalar(@seealso); 569 if($num > 2) { 570 # use commas up to this point 571 $and = $num - 1; 572 } 573 my $i = 0; 574 for my $k (@seealso) { 575 if(!$helplong{$k}) { 576 print STDERR "$f:$line:1:WARN: see-also a non-existing option: $k\n"; 577 } 578 my $l = manpageify($k); 579 my $sep = " and"; 580 if($and && ($i < $and)) { 581 $sep = ","; 582 } 583 $mstr .= sprintf "%s$l", $mstr?"$sep ":""; 584 $i++; 585 } 586 push @foot, seealso($standalone, $mstr); 587 588 if($requires) { 589 my $l = manpageify($long); 590 push @foot, "$l requires that the underlying libcurl". 591 " was built to support $requires. "; 592 } 593 if($mutexed) { 594 my @m=split(/ /, $mutexed); 595 my $mstr; 596 for my $k (@m) { 597 if(!$helplong{$k}) { 598 print STDERR "WARN: $f mutexes a non-existing option: $k\n"; 599 } 600 my $l = manpageify($k); 601 $mstr .= sprintf "%s$l", $mstr?" and ":""; 602 } 603 push @foot, overrides($standalone, 604 "This option is mutually exclusive to $mstr. "); 605 } 606 if($examples[0]) { 607 my $s =""; 608 $s="s" if($examples[1]); 609 print "\nExample$s:\n.nf\n"; 610 foreach my $e (@examples) { 611 $e =~ s!\$URL!https://example.com!g; 612 #$e =~ s/-/\\-/g; 613 #$e =~ s/\'/\\(aq/g; 614 # convert single backslahes to doubles 615 $e =~ s/\\/\\\\/g; 616 print " curl $e\n"; 617 } 618 print ".fi\n"; 619 } 620 if($added) { 621 push @foot, added($standalone, $added); 622 } 623 if($foot[0]) { 624 print "\n"; 625 my $f = join("", @foot); 626 $f =~ s/ +\z//; # remove trailing space 627 print "$f\n"; 628 } 629 return 0; 630} 631 632sub getshortlong { 633 my ($f)=@_; 634 open(F, "<:crlf", "$f"); 635 my $short; 636 my $long; 637 my $help; 638 my $arg; 639 my $protocols; 640 my $category; 641 my $start = 0; 642 while(<F>) { 643 if(!$start) { 644 if(/^---/) { 645 $start = 1; 646 } 647 next; 648 } 649 if(/^Short: (.)/i) { 650 $short=$1; 651 } 652 elsif(/^Long: (.*)/i) { 653 $long=$1; 654 } 655 elsif(/^Help: (.*)/i) { 656 $help=$1; 657 } 658 elsif(/^Arg: (.*)/i) { 659 $arg=$1; 660 } 661 elsif(/^Protocols: (.*)/i) { 662 $protocols=$1; 663 } 664 elsif(/^Category: (.*)/i) { 665 $category=$1; 666 } 667 elsif(/^---/) { 668 last; 669 } 670 } 671 close(F); 672 if($short) { 673 $optshort{$short}=$long; 674 } 675 if($long) { 676 $optlong{$long}=$short; 677 $helplong{$long}=$help; 678 $arglong{$long}=$arg; 679 $protolong{$long}=$protocols; 680 $catlong{$long}=$category; 681 } 682} 683 684sub indexoptions { 685 my (@files) = @_; 686 foreach my $f (@files) { 687 getshortlong($f); 688 } 689} 690 691sub header { 692 my ($f)=@_; 693 my $fh; 694 open($fh, "<:crlf", "$f"); 695 my @d = render($fh, $f, 1); 696 close($fh); 697 printdesc(@d); 698} 699 700sub listhelp { 701 print <<HEAD 702/*************************************************************************** 703 * _ _ ____ _ 704 * Project ___| | | | _ \\| | 705 * / __| | | | |_) | | 706 * | (__| |_| | _ <| |___ 707 * \\___|\\___/|_| \\_\\_____| 708 * 709 * Copyright (C) Daniel Stenberg, <daniel\@haxx.se>, et al. 710 * 711 * This software is licensed as described in the file COPYING, which 712 * you should have received as part of this distribution. The terms 713 * are also available at https://curl.se/docs/copyright.html. 714 * 715 * You may opt to use, copy, modify, merge, publish, distribute and/or sell 716 * copies of the Software, and permit persons to whom the Software is 717 * furnished to do so, under the terms of the COPYING file. 718 * 719 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 720 * KIND, either express or implied. 721 * 722 * SPDX-License-Identifier: curl 723 * 724 ***************************************************************************/ 725#include "tool_setup.h" 726#include "tool_help.h" 727 728/* 729 * DO NOT edit tool_listhelp.c manually. 730 * This source file is generated with the following command in an autotools 731 * build: 732 * 733 * "make listhelp" 734 */ 735 736const struct helptxt helptext[] = { 737HEAD 738 ; 739 foreach my $f (sort keys %helplong) { 740 my $long = $f; 741 my $short = $optlong{$long}; 742 my @categories = split ' ', $catlong{$long}; 743 my $bitmask = ' '; 744 my $opt; 745 746 if(defined($short) && $long) { 747 $opt = "-$short, --$long"; 748 } 749 elsif($long && !$short) { 750 $opt = " --$long"; 751 } 752 for my $i (0 .. $#categories) { 753 $bitmask .= 'CURLHELP_' . uc $categories[$i]; 754 # If not last element, append | 755 if($i < $#categories) { 756 $bitmask .= ' | '; 757 } 758 } 759 $bitmask =~ s/(?=.{76}).{1,76}\|/$&\n /g; 760 my $arg = $arglong{$long}; 761 if($arg) { 762 $opt .= " $arg"; 763 } 764 my $desc = $helplong{$f}; 765 $desc =~ s/\"/\\\"/g; # escape double quotes 766 767 my $line = sprintf " {\"%s\",\n \"%s\",\n %s},\n", $opt, $desc, $bitmask; 768 769 if(length($opt) > 78) { 770 print STDERR "WARN: the --$long name is too long\n"; 771 } 772 elsif(length($desc) > 78) { 773 print STDERR "WARN: the --$long description is too long\n"; 774 } 775 print $line; 776 } 777 print <<FOOT 778 { NULL, NULL, CURLHELP_HIDDEN } 779}; 780FOOT 781 ; 782} 783 784sub listcats { 785 my %allcats; 786 foreach my $f (sort keys %helplong) { 787 my @categories = split ' ', $catlong{$f}; 788 foreach (@categories) { 789 $allcats{$_} = undef; 790 } 791 } 792 my @categories; 793 foreach my $key (keys %allcats) { 794 push @categories, $key; 795 } 796 @categories = sort @categories; 797 unshift @categories, 'hidden'; 798 for my $i (0..$#categories) { 799 print '#define ' . 'CURLHELP_' . uc($categories[$i]) . ' ' . "1u << " . $i . "u\n"; 800 } 801} 802 803sub listglobals { 804 my (@files) = @_; 805 my @globalopts; 806 807 # Find all global options and output them 808 foreach my $f (sort @files) { 809 open(F, "<:crlf", "$f") || 810 next; 811 my $long; 812 my $start = 0; 813 while(<F>) { 814 if(/^---/) { 815 if(!$start) { 816 $start = 1; 817 next; 818 } 819 else { 820 last; 821 } 822 } 823 if(/^Long: *(.*)/i) { 824 $long=$1; 825 } 826 elsif(/^Scope: global/i) { 827 push @globalopts, $long; 828 last; 829 } 830 } 831 close(F); 832 } 833 return $ret if($ret); 834 for my $e (0 .. $#globalopts) { 835 $globals .= sprintf "%s--%s", $e?($globalopts[$e+1] ? ", " : " and "):"", 836 $globalopts[$e],; 837 } 838} 839 840sub noext { 841 my $in = $_[0]; 842 $in =~ s/\.d//; 843 return $in; 844} 845 846sub sortnames { 847 return noext($a) cmp noext($b); 848} 849 850sub mainpage { 851 my (@files) = @_; 852 my $ret; 853 my $fh; 854 open($fh, "<:crlf", "mainpage.idx") || 855 return 1; 856 857 print <<HEADER 858.\\" ************************************************************************** 859.\\" * _ _ ____ _ 860.\\" * Project ___| | | | _ \\| | 861.\\" * / __| | | | |_) | | 862.\\" * | (__| |_| | _ <| |___ 863.\\" * \\___|\\___/|_| \\_\\_____| 864.\\" * 865.\\" * Copyright (C) Daniel Stenberg, <daniel\@haxx.se>, et al. 866.\\" * 867.\\" * This software is licensed as described in the file COPYING, which 868.\\" * you should have received as part of this distribution. The terms 869.\\" * are also available at https://curl.se/docs/copyright.html. 870.\\" * 871.\\" * You may opt to use, copy, modify, merge, publish, distribute and/or sell 872.\\" * copies of the Software, and permit persons to whom the Software is 873.\\" * furnished to do so, under the terms of the COPYING file. 874.\\" * 875.\\" * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 876.\\" * KIND, either express or implied. 877.\\" * 878.\\" * SPDX-License-Identifier: curl 879.\\" * 880.\\" ************************************************************************** 881.\\" 882.\\" DO NOT EDIT. Generated by the curl project gen.pl man page generator. 883.\\" 884.TH curl 1 "$date" "curl $version" "curl Manual" 885HEADER 886 ; 887 888 while(<$fh>) { 889 my $f = $_; 890 chomp $f; 891 if($f =~ /^#/) { 892 # stardard comment 893 next; 894 } 895 if(/^%options/) { 896 # output docs for all options 897 foreach my $f (sort sortnames @files) { 898 $ret += single($f, 0); 899 } 900 } 901 else { 902 # render the file 903 header($f); 904 } 905 } 906 close($fh); 907 exit $ret if($ret); 908} 909 910sub showonly { 911 my ($f) = @_; 912 if(single($f, 1)) { 913 print STDERR "$f: failed\n"; 914 } 915} 916 917sub showprotocols { 918 my %prots; 919 foreach my $f (keys %optlong) { 920 my @p = split(/ /, $protolong{$f}); 921 for my $p (@p) { 922 $prots{$p}++; 923 } 924 } 925 for(sort keys %prots) { 926 printf "$_ (%d options)\n", $prots{$_}; 927 } 928} 929 930sub getargs { 931 my ($f, @s) = @_; 932 if($f eq "mainpage") { 933 listglobals(@s); 934 mainpage(@s); 935 return; 936 } 937 elsif($f eq "listhelp") { 938 listhelp(); 939 return; 940 } 941 elsif($f eq "single") { 942 showonly($s[0]); 943 return; 944 } 945 elsif($f eq "protos") { 946 showprotocols(); 947 return; 948 } 949 elsif($f eq "listcats") { 950 listcats(); 951 return; 952 } 953 954 print "Usage: gen.pl <mainpage/listhelp/single FILE/protos/listcats> [files]\n"; 955} 956 957#------------------------------------------------------------------------ 958 959my $cmd = shift @ARGV; 960my @files = @ARGV; # the rest are the files 961 962# learn all existing options 963indexoptions(@files); 964 965getargs($cmd, @files); 966