gen.pl 24 KB

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