blob: 040d5177ed978c797e67d76d98e71fa53d6cadf8 [file] [log] [blame]
xf.li6c8fc1e2023-08-12 00:11:09 -07001#!/usr/bin/env perl
2#***************************************************************************
3# _ _ ____ _
4# Project ___| | | | _ \| |
5# / __| | | | |_) | |
6# | (__| |_| | _ <| |___
7# \___|\___/|_| \_\_____|
8#
9# Copyright (C) 2016 - 2022, 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";