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