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