1 #!/usr/bin/env perl 2 #*************************************************************************** 3 # _ _ ____ _ 4 # Project ___| | | | _ \| | 5 # / __| | | | |_) | | 6 # | (__| |_| | _ <| |___ 7 # \___|\___/|_| \_\_____| 8 # 9 # Copyright (C) 2010-2011, Daniel Stenberg, <daniel (at] 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 http://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 # This script grew out of help from Przemyslaw Iskra and Balint Szilakszi 25 # a late evening in the #curl IRC channel on freenode. 26 # 27 28 use strict; 29 use warnings; 30 use vars qw($Cpreprocessor); 31 32 # 33 # configurehelp perl module is generated by configure script 34 # 35 my $rc = eval { 36 require configurehelp; 37 configurehelp->import(qw( 38 $Cpreprocessor 39 )); 40 1; 41 }; 42 # Set default values if configure has not generated a configurehelp.pm file. 43 # This is the case with cmake. 44 if (!$rc) { 45 $Cpreprocessor = 'cpp'; 46 } 47 48 # we may get the dir root pointed out 49 my $root=$ARGV[0] || "."; 50 51 # need an include directory when building out-of-tree 52 my $i = ($ARGV[1]) ? "-I$ARGV[1] " : ''; 53 54 my $h = "$root/include/curl/curl.h"; 55 my $mh = "$root/include/curl/multi.h"; 56 57 my $verbose=0; 58 my $summary=0; 59 my $misses=0; 60 61 my @syms; 62 my %doc; 63 my %rem; 64 65 open H_IN, "-|", "$Cpreprocessor $i$h" || die "Cannot preprocess curl.h"; 66 while ( <H_IN> ) { 67 if ( /enum\s+(\S+\s+)?{/ .. /}/ ) { 68 s/^\s+//; 69 next unless /^CURL/; 70 chomp; 71 s/[,\s].*//; 72 push @syms, $_; 73 } 74 } 75 close H_IN || die "Error preprocessing curl.h"; 76 77 sub scanheader { 78 my ($f)=@_; 79 open H, "<$f"; 80 while(<H>) { 81 if (/^#define (CURL[A-Za-z0-9_]*)/) { 82 push @syms, $1; 83 } 84 } 85 close H; 86 } 87 88 scanheader($h); 89 scanheader($mh); 90 91 open S, "<$root/docs/libcurl/symbols-in-versions"; 92 while(<S>) { 93 if(/(^CURL[^ \n]*) *(.*)/) { 94 my ($sym, $rest)=($1, $2); 95 if($doc{$sym}) { 96 print "Detected duplicate symbol: $sym\n"; 97 $misses++; 98 next; 99 } 100 $doc{$sym}=$sym; 101 my @a=split(/ +/, $rest); 102 if($a[2]) { 103 # this symbol is documented to have been present the last time 104 # in this release 105 $rem{$sym}=$a[2]; 106 } 107 } 108 } 109 close S; 110 111 my $ignored=0; 112 for my $e (sort @syms) { 113 # OBSOLETE - names that are just placeholders for a position where we 114 # previously had a name, that is now removed. The OBSOLETE names should 115 # never be used for anything. 116 # 117 # CURL_EXTERN - is a define used for libcurl functions that are external, 118 # public. No app or other code should ever use it. 119 # 120 # *_LAST and *_LASTENTRY are just prefix for the placeholders used for the 121 # last entry in many enum series. 122 # 123 124 if($e =~ /(OBSOLETE|^CURL_EXTERN|_LAST\z|_LASTENTRY\z)/) { 125 $ignored++; 126 next; 127 } 128 if($doc{$e}) { 129 if($verbose) { 130 print $e."\n"; 131 } 132 $doc{$e}="used"; 133 next; 134 } 135 else { 136 print $e."\n"; 137 $misses++; 138 } 139 } 140 141 # 142 # now scan through all symbols that were present in the symbols-in-versions 143 # but not in the headers 144 # 145 # If the symbols were marked 'removed' in symbols-in-versions we don't output 146 # anything about it since that is perfectly fine. 147 # 148 149 my $anyremoved; 150 151 for my $e (sort keys %doc) { 152 if(($doc{$e} ne "used") && !$rem{$e}) { 153 154 if(!$anyremoved++) { 155 print "Missing symbols mentioned in symbols-in-versions\n"; 156 print "Add them to a header, or mark them as removed.\n"; 157 } 158 159 print "$e\n"; 160 $misses++; 161 } 162 } 163 164 if($summary) { 165 print "Summary:\n"; 166 printf "%d symbols in headers (out of which %d are ignored)\n", scalar(@syms), 167 $ignored; 168 printf "%d symbols in headers are interesting\n", 169 scalar(@syms)- $ignored; 170 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); 171 printf "%d symbols in symbols-in-versions should match the ones in headers\n", scalar(keys %doc) - scalar(keys %rem); 172 } 173 174 if($misses) { 175 exit 2; # there are stuff to attend to! 176 } 177