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