1#!/usr/bin/env perl 2#*************************************************************************** 3# _ _ ____ _ 4# Project ___| | | | _ \| | 5# / __| | | | |_) | | 6# | (__| |_| | _ <| |___ 7# \___|\___/|_| \_\_____| 8# 9# Copyright (C) 2016, 2017, 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 142 # pretend these options without -no exist in curl.1 and tool_help.c 143 '--alpn' => 6, 144 '--npn' => 6, 145 '--eprt' => 6, 146 '--epsv' => 6, 147 '--keepalive' => 6, 148 '-N, --buffer' => 6, 149 '--sessionid' => 6, 150 151 # deprecated options do not need to be in tool_help.c nor curl.1 152 '--krb4' => 6, 153 '--ftp-ssl' => 6, 154 '--ftp-ssl-reqd' => 6, 155 156 # for tests and debug only, can remain hidden 157 '--test-event' => 6, 158 '--wdebug' => 6, 159 ); 160 161 162######################################################################### 163# parse the curl code that parses the command line arguments! 164open(R, "<$root/src/tool_getparam.c") || 165 die "no input file"; 166my $list; 167my @getparam; # store all parsed parameters 168 169while(<R>) { 170 chomp; 171 my $l= $_; 172 if(/struct LongShort aliases/) { 173 $list=1; 174 } 175 elsif($list) { 176 if( /^ \{([^,]*), *([^ ]*)/) { 177 my ($s, $l)=($1, $2); 178 my $sh; 179 my $lo; 180 my $title; 181 if($l =~ /\"(.*)\"/) { 182 # long option 183 $lo = $1; 184 $title="--$lo"; 185 } 186 if($s =~ /\"(.)\"/) { 187 # a short option 188 $sh = $1; 189 $title="-$sh, $title"; 190 } 191 push @getparam, $title; 192 $opts{$title} |= 1; 193 } 194 } 195} 196close(R); 197 198######################################################################### 199# parse the curl.1 man page, extract all documented command line options 200# The man page may or may not be rebuilt, so check both possible locations 201open(R, "<$buildroot/docs/curl.1") || open(R, "<$root/docs/curl.1") || 202 die "no input file"; 203my @manpage; # store all parsed parameters 204while(<R>) { 205 chomp; 206 my $l= $_; 207 if(/^\.IP \"(-[^\"]*)\"/) { 208 my $str = $1; 209 my $combo; 210 if($str =~ /^-(.), --([a-z0-9.-]*)/) { 211 # figure out the -short, --long combo 212 $combo = "-$1, --$2"; 213 } 214 elsif($str =~ /^--([a-z0-9.-]*)/) { 215 # figure out the --long name 216 $combo = "--$1"; 217 } 218 if($combo) { 219 push @manpage, $combo; 220 $opts{$combo} |= 2; 221 } 222 } 223} 224close(R); 225 226 227######################################################################### 228# parse the curl code that outputs the curl -h list 229open(R, "<$root/src/tool_help.c") || 230 die "no input file"; 231my @toolhelp; # store all parsed parameters 232while(<R>) { 233 chomp; 234 my $l= $_; 235 if(/^ \{\" *(.*)/) { 236 my $str=$1; 237 my $combo; 238 if($str =~ /^-(.), --([a-z0-9.-]*)/) { 239 # figure out the -short, --long combo 240 $combo = "-$1, --$2"; 241 } 242 elsif($str =~ /^--([a-z0-9.-]*)/) { 243 # figure out the --long name 244 $combo = "--$1"; 245 } 246 if($combo) { 247 push @toolhelp, $combo; 248 $opts{$combo} |= 4; 249 } 250 251 } 252} 253close(R); 254 255# 256# Now we have three arrays with options to cross-reference. 257 258foreach my $o (keys %opts) { 259 my $where = $opts{$o}; 260 261 if($where != 7) { 262 # this is not in all three places 263 $errors++; 264 my $exists; 265 my $missing; 266 if($where & 1) { 267 $exists=" tool_getparam.c"; 268 } 269 else { 270 $missing=" tool_getparam.c"; 271 } 272 if($where & 2) { 273 $exists.= " curl.1"; 274 } 275 else { 276 $missing.= " curl.1"; 277 } 278 if($where & 4) { 279 $exists .= " tool_help.c"; 280 } 281 else { 282 $missing .= " tool_help.c"; 283 } 284 285 print STDERR "$o is not in$missing (but in$exists)\n"; 286 } 287} 288 289exit $errors; 290