test1119.pl (6684B)
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 # This script grew out of help from Przemyslaw Iskra and Balint Szilakszi 27 # a late evening in the #curl IRC channel. 28 # 29 30 use strict; 31 use warnings; 32 use vars qw($Cpreprocessor); 33 34 # 35 # configurehelp perl module is generated by configure script 36 # 37 my $rc = eval { 38 require configurehelp; 39 configurehelp->import(qw( 40 $Cpreprocessor 41 )); 42 1; 43 }; 44 # Set default values if configure has not generated a configurehelp.pm file. 45 # This is the case with cmake. 46 if(!$rc) { 47 $Cpreprocessor = 'cpp'; 48 } 49 50 # we may get the dir root pointed out 51 my $root=$ARGV[0] || "."; 52 53 # need an include directory when building out-of-tree 54 my $i = ($ARGV[1]) ? "-I$ARGV[1] " : ''; 55 56 my $verbose=0; 57 my $summary=0; 58 my $misses=0; 59 60 my @manrefs; 61 my @syms; 62 my %doc; 63 my %rem; 64 65 # scanenum runs the preprocessor on curl.h so it will process all enums 66 # included by it, which *should* be all headers 67 sub scanenum { 68 my ($file) = @_; 69 open my $h_in, "-|", "$Cpreprocessor $i$file" || die "Cannot preprocess $file"; 70 while(<$h_in>) { 71 if(/enum\s+(\S+\s+)?{/ .. /}/) { 72 s/^\s+//; 73 next unless /^CURL/; 74 chomp; 75 s/[,\s].*//; 76 push @syms, $_; 77 } 78 } 79 close $h_in || die "Error preprocessing $file"; 80 } 81 82 sub scanheader { 83 my ($f)=@_; 84 open my $h, "<", "$f"; 85 while(<$h>) { 86 if(/^#define ((LIB|)CURL[A-Za-z0-9_]*)/) { 87 push @syms, $1; 88 } 89 } 90 close $h; 91 } 92 93 sub scanallheaders { 94 my $d = "$root/include/curl"; 95 opendir(my $dh, $d) || 96 die "Can't opendir: $!"; 97 my @headers = grep { /.h\z/ } readdir($dh); 98 closedir $dh; 99 foreach my $h (@headers) { 100 scanenum("$d/$h"); 101 scanheader("$d/$h"); 102 } 103 } 104 105 sub checkmanpage { 106 my ($m) = @_; 107 108 open(my $mh, "<", "$m"); 109 my $line = 1; 110 while(<$mh>) { 111 # strip off formatting 112 $_ =~ s/(^|[^A-Z0-9])[*_]+/ /; 113 # detect global-looking 'CURL[BLABLA]_*' symbols 114 while(s/\W(CURL(AUTH|E|H|MOPT|OPT|SHOPT|UE|M|SSH|SSLBACKEND|HEADER|FORM|FTP|PIPE|MIMEOPT|GSSAPI|ALTSVC|PROTO|PROXY|UPART|USESSL|_READFUNC|_WRITEFUNC|_CSELECT|_FORMADD|_IPRESOLVE|_REDIR|_RTSPREQ|_TIMECOND|_VERSION)_[a-zA-Z0-9_]+)//) { 115 my $s = $1; 116 # skip two "special" ones 117 if($s !~ /^(CURLE_OBSOLETE|CURLOPT_TEMPLATE)/) { 118 push @manrefs, "$1:$m:$line"; 119 } 120 } 121 $line++; 122 } 123 close($mh); 124 } 125 126 sub scanman_md_dir { 127 my ($d) = @_; 128 opendir(my $dh, $d) || 129 die "Can't opendir: $!"; 130 my @mans = grep { /.md\z/ } readdir($dh); 131 closedir $dh; 132 for my $m (@mans) { 133 checkmanpage("$d/$m"); 134 } 135 } 136 137 138 scanallheaders(); 139 scanman_md_dir("$root/docs/libcurl"); 140 scanman_md_dir("$root/docs/libcurl/opts"); 141 142 open my $s, "<", "$root/docs/libcurl/symbols-in-versions"; 143 while(<$s>) { 144 if(/(^[^ \n]+) +(.*)/) { 145 my ($sym, $rest)=($1, $2); 146 if($doc{$sym}) { 147 print "Detected duplicate symbol: $sym\n"; 148 $misses++; 149 next; 150 } 151 $doc{$sym}=$sym; 152 my @a=split(/ +/, $rest); 153 if($a[2]) { 154 # this symbol is documented to have been present the last time 155 # in this release 156 $rem{$sym}=$a[2]; 157 } 158 } 159 } 160 close $s; 161 162 my $ignored=0; 163 for my $e (sort @syms) { 164 # OBSOLETE - names that are just placeholders for a position where we 165 # previously had a name, that is now removed. The OBSOLETE names should 166 # never be used for anything. 167 # 168 # CURL_EXTERN - is a define used for libcurl functions that are external, 169 # public. No app or other code should ever use it. 170 # 171 # CURLINC_ - defines for header dual-include prevention, ignore those. 172 # 173 # CURL_TEMP_ - are defined and *undefined* again within the file 174 # 175 # *_LAST and *_LASTENTRY are just prefix for the placeholders used for the 176 # last entry in many enum series. 177 # 178 179 if($e =~ /(OBSOLETE|CURLE_RESERVED|^CURL_EXTERN|^CURLINC_|_LAST\z|_LASTENTRY\z|^CURL_TEMP_)/) { 180 $ignored++; 181 next; 182 } 183 if($doc{$e}) { 184 if($verbose) { 185 print $e."\n"; 186 } 187 $doc{$e}="used"; 188 next; 189 } 190 else { 191 print $e."\n"; 192 $misses++; 193 } 194 } 195 196 # 197 # now scan through all symbols that were present in the symbols-in-versions 198 # but not in the headers 199 # 200 # If the symbols were marked 'removed' in symbols-in-versions we don't output 201 # anything about it since that is perfectly fine. 202 # 203 204 my $anyremoved; 205 206 for my $e (sort keys %doc) { 207 if(($doc{$e} ne "used") && !$rem{$e}) { 208 209 if(!$anyremoved++) { 210 print "Missing symbols mentioned in symbols-in-versions\n"; 211 print "Add them to a header, or mark them as removed.\n"; 212 } 213 214 print "$e\n"; 215 $misses++; 216 } 217 } 218 219 my %warned; 220 for my $r (@manrefs) { 221 if($r =~ /^([^:]+):(.*)/) { 222 my ($sym, $file)=($1, $2); 223 if(!$doc{$sym} && !$warned{$sym, $file}) { 224 print "$file: $sym is not a public symbol\n"; 225 $warned{$sym, $file} = 1; 226 } 227 } 228 } 229 230 if($summary) { 231 print "Summary:\n"; 232 printf "%d symbols in headers (out of which %d are ignored)\n", scalar(@syms), 233 $ignored; 234 printf "%d symbols in headers are interesting\n", 235 scalar(@syms)- $ignored; 236 printf "%d symbols are listed in symbols-in-versions\n (out of which %d are listed as removed)\n", scalar(keys %doc), scalar(keys %rem); 237 printf "%d symbols in symbols-in-versions should match the ones in headers\n", scalar(keys %doc) - scalar(keys %rem); 238 } 239 240 if($misses) { 241 exit 0; # there are stuff to attend to! 242 } 243 else { 244 print "OK\n"; 245 }