• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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# Scan symbols-in-version (which is verified to be correct by test 1119), then
27# verify that each option mention in there that should have its own man page
28# actually does.
29#
30# In addition, make sure that every current option to curl_easy_setopt,
31# curl_easy_getinfo and curl_multi_setopt are also mentioned in their
32# corresponding main (index) man page.
33#
34# src/tool_getparam.c lists all options curl can parse
35# docs/curl.1 documents all command line options
36# src/tool_listhelp.c outputs all options with curl -h
37# - make sure they're all in sync
38#
39# Output all deviances to stderr.
40
41use strict;
42use warnings;
43
44# we may get the dir roots pointed out
45my $root=$ARGV[0] || ".";
46my $buildroot=$ARGV[1] || ".";
47my $syms = "$root/docs/libcurl/symbols-in-versions";
48my $curlh = "$root/include/curl/curl.h";
49my $errors=0;
50
51# the prepopulated alias list is the CURLINFO_* defines that are used for the
52# debug function callback and the fact that they use the same prefix as the
53# curl_easy_getinfo options was a mistake.
54my %alias = (
55    'CURLINFO_DATA_IN' => 'none',
56    'CURLINFO_DATA_OUT' => 'none',
57    'CURLINFO_END' => 'none',
58    'CURLINFO_HEADER_IN' => 'none',
59    'CURLINFO_HEADER_OUT' => 'none',
60    'CURLINFO_LASTONE' => 'none',
61    'CURLINFO_NONE' => 'none',
62    'CURLINFO_SSL_DATA_IN' => 'none',
63    'CURLINFO_SSL_DATA_OUT' => 'none',
64    'CURLINFO_TEXT' => 'none'
65    );
66
67sub scanmanpage {
68    my ($file, @words) = @_;
69
70    open(M, "<$file");
71    my @m;
72    while(<M>) {
73        if($_ =~ /^\.IP (.*)/) {
74            my $w = $1;
75            # "unquote" minuses
76            $w =~ s/\\-/-/g;
77            push @m, $w;
78        }
79    }
80    close(M);
81
82    foreach my $m (@words) {
83        my @g = grep(/$m/, @m);
84        if(!$g[0]) {
85            print STDERR "Missing mention of $m in $file\n";
86            $errors++;
87        }
88    }
89}
90
91# check for define alises
92open(R, "<$curlh") ||
93    die "no curl.h";
94while(<R>) {
95    if(/^\#define (CURL(OPT|INFO|MOPT)_\w+) (.*)/) {
96        $alias{$1}=$3;
97    }
98}
99close(R);
100
101my @curlopt;
102my @curlinfo;
103my @curlmopt;
104open(R, "<$syms") ||
105    die "no input file";
106while(<R>) {
107    chomp;
108    my $l= $_;
109    if($l =~ /(CURL(OPT|INFO|MOPT)_\w+) *([0-9.]*) *([0-9.-]*) *([0-9.]*)/) {
110        my ($opt, $type, $add, $dep, $rem) = ($1, $2, $3, $4, $5);
111
112        if($alias{$opt}) {
113            #print "$opt => $alias{$opt}\n";
114        }
115        elsif($rem) {
116            # $opt was removed in $rem
117            # so don't check for that
118        }
119        else {
120            if($type eq "OPT") {
121                push @curlopt, $opt,
122            }
123            elsif($type eq "INFO") {
124                push @curlinfo, $opt,
125            }
126            elsif($type eq "MOPT") {
127                push @curlmopt, $opt,
128            }
129            if(! -f "$root/docs/libcurl/opts/$opt.3") {
130                print STDERR "Missing $opt.3\n";
131                $errors++;
132            }
133        }
134    }
135}
136close(R);
137
138scanmanpage("$root/docs/libcurl/curl_easy_setopt.3", @curlopt);
139scanmanpage("$root/docs/libcurl/curl_easy_getinfo.3", @curlinfo);
140scanmanpage("$root/docs/libcurl/curl_multi_setopt.3", @curlmopt);
141
142# using this hash array, we can skip specific options
143my %opts = (
144    # pretend these --no options exists in tool_getparam.c
145    '--no-alpn' => 1,
146    '--no-npn' => 1,
147    '-N, --no-buffer' => 1,
148    '--no-sessionid' => 1,
149    '--no-keepalive' => 1,
150    '--no-progress-meter' => 1,
151    '--no-clobber' => 1,
152
153    # pretend these options without -no exist in curl.1 and tool_listhelp.c
154    '--alpn' => 6,
155    '--npn' => 6,
156    '--eprt' => 6,
157    '--epsv' => 6,
158    '--keepalive' => 6,
159    '-N, --buffer' => 6,
160    '--sessionid' => 6,
161    '--progress-meter' => 6,
162    '--clobber' => 6,
163
164    # deprecated options do not need to be in tool_help.c nor curl.1
165    '--krb4' => 6,
166    '--ftp-ssl' => 6,
167    '--ftp-ssl-reqd' => 6,
168
169    # for tests and debug only, can remain hidden
170    '--test-event' => 6,
171    '--wdebug' => 6,
172    );
173
174
175#########################################################################
176# parse the curl code that parses the command line arguments!
177open(R, "<$root/src/tool_getparam.c") ||
178    die "no input file";
179my $list;
180my @getparam; # store all parsed parameters
181
182while(<R>) {
183    chomp;
184    my $l= $_;
185    if(/struct LongShort aliases/) {
186        $list=1;
187    }
188    elsif($list) {
189        if( /^  \{([^,]*), *([^ ]*)/) {
190            my ($s, $l)=($1, $2);
191            my $sh;
192            my $lo;
193            my $title;
194            if($l =~ /\"(.*)\"/) {
195                # long option
196                $lo = $1;
197                $title="--$lo";
198            }
199            if($s =~ /\"(.)\"/) {
200                # a short option
201                $sh = $1;
202                $title="-$sh, $title";
203            }
204            push @getparam, $title;
205            $opts{$title} |= 1;
206        }
207    }
208}
209close(R);
210
211#########################################################################
212# parse the curl.1 man page, extract all documented command line options
213# The man page may or may not be rebuilt, so check both possible locations
214open(R, "<$buildroot/docs/curl.1") || open(R, "<$root/docs/curl.1") ||
215    die "no input file";
216my @manpage; # store all parsed parameters
217while(<R>) {
218    chomp;
219    my $l= $_;
220    $l =~ s/\\-/-/g;
221    if($l =~ /^\.IP \"(-[^\"]*)\"/) {
222        my $str = $1;
223        my $combo;
224        if($str =~ /^-(.), --([a-z0-9.-]*)/) {
225            # figure out the -short, --long combo
226            $combo = "-$1, --$2";
227        }
228        elsif($str =~ /^--([a-z0-9.-]*)/) {
229            # figure out the --long name
230            $combo = "--$1";
231        }
232        if($combo) {
233            push @manpage, $combo;
234            $opts{$combo} |= 2;
235        }
236    }
237}
238close(R);
239
240
241#########################################################################
242# parse the curl code that outputs the curl -h list
243open(R, "<$root/src/tool_listhelp.c") ||
244    die "no input file";
245my @toolhelp; # store all parsed parameters
246while(<R>) {
247    chomp;
248    my $l= $_;
249    if(/^  \{\" *(.*)/) {
250        my $str=$1;
251        my $combo;
252        if($str =~ /^-(.), --([a-z0-9.-]*)/) {
253            # figure out the -short, --long combo
254            $combo = "-$1, --$2";
255        }
256        elsif($str =~ /^--([a-z0-9.-]*)/) {
257            # figure out the --long name
258            $combo = "--$1";
259        }
260        if($combo) {
261            push @toolhelp, $combo;
262            $opts{$combo} |= 4;
263        }
264
265    }
266}
267close(R);
268
269#
270# Now we have three arrays with options to cross-reference.
271
272foreach my $o (keys %opts) {
273    my $where = $opts{$o};
274
275    if($where != 7) {
276        # this is not in all three places
277        $errors++;
278        my $exists;
279        my $missing;
280        if($where & 1) {
281            $exists=" tool_getparam.c";
282        }
283        else {
284            $missing=" tool_getparam.c";
285        }
286        if($where & 2) {
287            $exists.= " curl.1";
288        }
289        else {
290            $missing.= " curl.1";
291        }
292        if($where & 4) {
293            $exists .= " tool_listhelp.c";
294        }
295        else {
296            $missing .= " tool_listhelp.c";
297        }
298
299        print STDERR "$o is not in$missing (but in$exists)\n";
300    }
301}
302
303print STDERR "$errors\n";
304