1#!/usr/bin/env perl
2#***************************************************************************
3#                                  _   _ ____  _
4#  Project                     ___| | | |  _ \| |
5#                             / __| | | | |_) | |
6#                            | (__| |_| |  _ <| |___
7#                             \___|\___/|_| \_\_____|
8#
9# Copyright (C) 2010-2021, 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###########################################################################
23#
24# This script grew out of help from Przemyslaw Iskra and Balint Szilakszi
25# a late evening in the #curl IRC channel.
26#
27
28use strict;
29use warnings;
30use vars qw($Cpreprocessor);
31
32#
33# configurehelp perl module is generated by configure script
34#
35my $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.
44if (!$rc) {
45    $Cpreprocessor = 'cpp';
46}
47
48my $verbose=0;
49
50# verbose mode when -v is the first argument
51if($ARGV[0] eq "-v") {
52    $verbose=1;
53    shift;
54}
55
56# we may get the dir root pointed out
57my $root=$ARGV[0] || ".";
58
59# need an include directory when building out-of-tree
60my $i = ($ARGV[1]) ? "-I$ARGV[1] " : '';
61
62my $incdir = "$root/include/curl";
63
64my $summary=0;
65my $misses=0;
66
67my @syms;
68my %doc;
69my %rem;
70
71sub scanenums {
72    my ($file)=@_;
73    my $skipit = 0;
74
75    open H_IN, "-|", "$Cpreprocessor $i$file" || die "Cannot preprocess $file";
76    while ( <H_IN> ) {
77        my ($line, $linenum) = ($_, $.);
78        if( /^#(line|) (\d+) \"(.*)\"/) {
79            # if the included file isn't in our incdir, then we skip this section
80            # until next #line
81            #
82            if($3 !~ /^$incdir/) {
83                $skipit = 1;
84                next;
85            }
86            # parse this!
87            $skipit = 0;
88            next;
89        }
90        if($skipit) {
91            next;
92        }
93        if (/^#/) {
94            next;
95        }
96        if ( /enum\s+(\S+\s+)?{/ .. /}/ ) {
97            s/^\s+//;
98            chomp;
99            s/[,\s].*//;
100            if(($_ !~ /\}(;|)/) &&
101               ($_ ne "typedef") &&
102               ($_ ne "enum") &&
103               ($_ !~ /^[ \t]*$/)) {
104                if($verbose) {
105                    print "Source: $Cpreprocessor $i$file\n";
106                    print "Symbol: $_\n";
107                    print "Line #$linenum: $line\n\n";
108                }
109                push @syms, $_;
110            }
111        }
112    }
113    close H_IN || die "Error preprocessing $file";
114}
115
116sub scanheader {
117    my ($f)=@_;
118    scanenums($f);
119    open H, "<$f";
120    while(<H>) {
121        my ($line, $linenum) = ($_, $.);
122        if (/^#define +([^ \n]*)/) {
123            if($verbose) {
124                print "Source: $f\n";
125                print "Symbol: $1\n";
126                print "Line #$linenum: $line\n\n";
127            }
128            push @syms, $1;
129        }
130    }
131    close H;
132}
133
134
135opendir(my $dh, $incdir) || die "Can't opendir $incdir: $!";
136my @hfiles = grep { /\.h$/ } readdir($dh);
137closedir $dh;
138
139for(@hfiles) {
140    scanheader("$incdir/$_");
141}
142
143my $errors = 0;
144for my $s (@syms) {
145    if($s !~ /^(lib|)curl/i) {
146        print "Bad symbols in public header files:\n" if(!$errors);
147        $errors++;
148        print "  $s\n";
149    }
150}
151if($errors) {
152    exit 1;
153}
154printf "%d fine symbols found\n", scalar(@syms);
155