0c27b3fe77ac1d5094ba3521e8142d9e7973133fMark Andrews# Copyright (C) 2000, 2001, 2004, 2007, 2012, 2016 Internet Systems Consortium, Inc. ("ISC")
0c27b3fe77ac1d5094ba3521e8142d9e7973133fMark Andrews# This Source Code Form is subject to the terms of the Mozilla Public
0c27b3fe77ac1d5094ba3521e8142d9e7973133fMark Andrews# License, v. 2.0. If a copy of the MPL was not distributed with this
0c27b3fe77ac1d5094ba3521e8142d9e7973133fMark Andrews# file, You can obtain one at http://mozilla.org/MPL/2.0/.
9bb05852fed91ff3913601b7ed8e43e711aa9094David Lawrence# Rudimentary, primarily for use by the developers.
9bb05852fed91ff3913601b7ed8e43e711aa9094David Lawrence# This just evolved with no serious attempt at making it
9bb05852fed91ff3913601b7ed8e43e711aa9094David Lawrence# bulletproof or foolproof. Or pretty even. Probably would
9bb05852fed91ff3913601b7ed8e43e711aa9094David Lawrence# have done it differently if it were actually designed as opposed
9bb05852fed91ff3913601b7ed8e43e711aa9094David Lawrence# to just growing as a multi-tentacled thing as various messages
9bb05852fed91ff3913601b7ed8e43e711aa9094David Lawrence# were either added or selectively silenced.
595babf6279b0f07895c42fd1b74a5f437ccacefDavid Lawrence# XXX many warnings should not be made unless the header will be a public file
0978cb57f3ef18a63748699a5b1dd607866f6107David Lawrenceuse vars qw($debug $isc_includes $dns_includes $lwres_includes
0978cb57f3ef18a63748699a5b1dd607866f6107David Lawrence$isc_includes = "-Ilib/isc/include -Ilib/isc/unix/include " .
0978cb57f3ef18a63748699a5b1dd607866f6107David Lawrence$dns_includes = "-Ilib/dns/include -Ilib/dns/sec/dst/include";
9bb05852fed91ff3913601b7ed8e43e711aa9094David Lawrence$0 =~ s%.*/%%;
9bb05852fed91ff3913601b7ed8e43e711aa9094David Lawrencedie "Usage: $0 [-debug] headerfile ...\n" unless @ARGV > 0;
9bb05852fed91ff3913601b7ed8e43e711aa9094David Lawrenceunless (-f 'configure.in') {
9bb05852fed91ff3913601b7ed8e43e711aa9094David Lawrence die "$0: run from top of bind9 source tree\n";
9bb05852fed91ff3913601b7ed8e43e711aa9094David Lawrence# Outer loop runs once for each file.
9bb05852fed91ff3913601b7ed8e43e711aa9094David Lawrence unless ($file =~ /\.h$/) {
9bb05852fed91ff3913601b7ed8e43e711aa9094David Lawrence print "$0: skipping non-header file $file\n";
9bb05852fed91ff3913601b7ed8e43e711aa9094David Lawrence die "$0: $file: no such file\n" unless -f $file;
595babf6279b0f07895c42fd1b74a5f437ccacefDavid Lawrence # header file fragments; ignore
595babf6279b0f07895c42fd1b74a5f437ccacefDavid Lawrence # XXX rdatastruct itself is moderately tricky.
595babf6279b0f07895c42fd1b74a5f437ccacefDavid Lawrence next if $file =~ m%/rdatastruct(pre|suf)\.h$%;
595babf6279b0f07895c42fd1b74a5f437ccacefDavid Lawrence # From external sources; ignore.
595babf6279b0f07895c42fd1b74a5f437ccacefDavid Lawrence next if $file =~ m%lib/dns/sec/(dnssafe|openssl)%m;
595babf6279b0f07895c42fd1b74a5f437ccacefDavid Lawrence # Totally wrong platform; ignore.
9bb05852fed91ff3913601b7ed8e43e711aa9094David Lawrence $tmpfile =~ s/\.h$/.c/;
9bb05852fed91ff3913601b7ed8e43e711aa9094David Lawrence $file =~ m%(.*/)?(.*)/(.*)\.h%;
9bb05852fed91ff3913601b7ed8e43e711aa9094David Lawrence $symbol =~ s/\\-/_/g;
9bb05852fed91ff3913601b7ed8e43e711aa9094David Lawrence if (! m%^\#ifndef\ $symbol\n
9bb05852fed91ff3913601b7ed8e43e711aa9094David Lawrence \#define\ $symbol\ 1\n
9bb05852fed91ff3913601b7ed8e43e711aa9094David Lawrence \#endif\ /\*\ $symbol\ \*/\n
595babf6279b0f07895c42fd1b74a5f437ccacefDavid Lawrence print "$file has non-conforming wrapper for symbol $symbol\n"
0978cb57f3ef18a63748699a5b1dd607866f6107David Lawrence my $lib = $file =~ /lwres/ ? "lwres" : "isc";
9bb05852fed91ff3913601b7ed8e43e711aa9094David Lawrence # check use of macros without having included proper header for them.
0978cb57f3ef18a63748699a5b1dd607866f6107David Lawrence ! m%^#include <$lib/lang\.h>$%m) {
0978cb57f3ef18a63748699a5b1dd607866f6107David Lawrence print "$file has $1 without <$lib/lang.h>\n";
9bb05852fed91ff3913601b7ed8e43e711aa9094David Lawrence if (/$nocomment.*ISC_EVENTCLASS_/m && ! m%^#include <isc/eventclass\.h>%m) {
595babf6279b0f07895c42fd1b74a5f437ccacefDavid Lawrence print "$file has ISC_EVENTCLASS_ without <isc/eventclass.h>\n"
9bb05852fed91ff3913601b7ed8e43e711aa9094David Lawrence ! m%^#include <isc/resultclass\.h>%m) {
595babf6279b0f07895c42fd1b74a5f437ccacefDavid Lawrence print "$file has ISC_RESULTCLASS_ without <isc/resultclass.h>\n"
9bb05852fed91ff3913601b7ed8e43e711aa9094David Lawrence ! m%^#include <isc/(types|boolean).h>%m) {
595babf6279b0f07895c42fd1b74a5f437ccacefDavid Lawrence print "$file has ISC_TRUE/FALSE/TF without <isc/(boolean|types).h>\n"
9bb05852fed91ff3913601b7ed8e43e711aa9094David Lawrence ! m%^#include <isc/platform.h>%m) {
595babf6279b0f07895c42fd1b74a5f437ccacefDavid Lawrence print "$file has ISC_PLATFORM_ without <isc/platform.h>\n"
0978cb57f3ef18a63748699a5b1dd607866f6107David Lawrence if ($file !~ m%isc/magic\.h$% && $lib ne "lwres") {
595babf6279b0f07895c42fd1b74a5f437ccacefDavid Lawrence print "$file has ISC_MAGIC_VALID without <isc/magic.h>\n"
595babf6279b0f07895c42fd1b74a5f437ccacefDavid Lawrence if /$nocomment.*ISC_MAGIC_VALID/m && ! m%^#include <isc/magic.h>%m;
595babf6279b0f07895c42fd1b74a5f437ccacefDavid Lawrence print "$file could use ISC_MAGIC_VALID\n" if /^$nocomment.*->magic ==/m;
9bb05852fed91ff3913601b7ed8e43e711aa9094David Lawrence ! m%^#include <\L$1\E/result.h>%m) {
595babf6279b0f07895c42fd1b74a5f437ccacefDavid Lawrence print "$file has $1_R_ without <\L$1\E/result.h>\n"
9bb05852fed91ff3913601b7ed8e43e711aa9094David Lawrence if (/^$nocomment(?!#define)[a-z].*([a-zA-Z0-9]\([^;]*\);)/m &&
0978cb57f3ef18a63748699a5b1dd607866f6107David Lawrence ! m%^#include <$lib/lang.h>%m) {
0978cb57f3ef18a63748699a5b1dd607866f6107David Lawrence print "$file has declarations without <$lib/lang.h>\n";
595babf6279b0f07895c42fd1b74a5f437ccacefDavid Lawrence # First see whether it can be compiled without any additional includes.
595babf6279b0f07895c42fd1b74a5f437ccacefDavid Lawrence # Only bother doing this for files that will be installed as public
595babf6279b0f07895c42fd1b74a5f437ccacefDavid Lawrence # headers (thus weeding out, for example, all of the dns/rdata/*/*.h)
595babf6279b0f07895c42fd1b74a5f437ccacefDavid Lawrence if ($file =~ m%/include/% && system("cp $file $tmpfile") == 0) {
0978cb57f3ef18a63748699a5b1dd607866f6107David Lawrence if (compile($file, $tmpfile, $objfile) != 0) {
595babf6279b0f07895c42fd1b74a5f437ccacefDavid Lawrence print "$file does not compile stand-alone\n";
595babf6279b0f07895c42fd1b74a5f437ccacefDavid Lawrence my ($elided, $comment, $prefix_extend, $body);
595babf6279b0f07895c42fd1b74a5f437ccacefDavid Lawrence # 1 23 4 5 6 78
595babf6279b0f07895c42fd1b74a5f437ccacefDavid Lawrence if (m%(\A\Q$prefix\E((.*\n)*?))(\#include .*(<.*?>)(.*)\n)((.*\n)*)%) {
9bb05852fed91ff3913601b7ed8e43e711aa9094David Lawrence if ($@ ne "") {
595babf6279b0f07895c42fd1b74a5f437ccacefDavid Lawrence print "$file processing failed: $@\n";
9bb05852fed91ff3913601b7ed8e43e711aa9094David Lawrence print STDERR "$file checking $elided\n" if $debug;
595babf6279b0f07895c42fd1b74a5f437ccacefDavid Lawrence # Can mark in the header file when a #include should stay even
595babf6279b0f07895c42fd1b74a5f437ccacefDavid Lawrence # though it might not appear that way otherwise.
0978cb57f3ef18a63748699a5b1dd607866f6107David Lawrence next if $comment =~ /require|provide|extend|define|contract|ensure/i;
9bb05852fed91ff3913601b7ed8e43e711aa9094David Lawrence # Special exceptions.
9bb05852fed91ff3913601b7ed8e43e711aa9094David Lawrence # XXXDCL some of these should be perhaps generalized (ie, look for
9bb05852fed91ff3913601b7ed8e43e711aa9094David Lawrence # ISC_(LINK|LIST)_ when using <isc/list.h>.
9bb05852fed91ff3913601b7ed8e43e711aa9094David Lawrence if (($file =~ m%isc/log\.h$% && $elided eq "<syslog.h>") ||
9bb05852fed91ff3913601b7ed8e43e711aa9094David Lawrence ($file =~ m%isc/print\.h$% && $elided =~ /^<std(arg|def)\.h>$/) ||
9bb05852fed91ff3913601b7ed8e43e711aa9094David Lawrence ($file =~ m%isc/string\.h$% && $elided eq "<string.h>") ||
9bb05852fed91ff3913601b7ed8e43e711aa9094David Lawrence $elided =~ m%^<isc/(boolean|int|offset)\.h>$%) ||
9bb05852fed91ff3913601b7ed8e43e711aa9094David Lawrence if ($elided =~ m%^<(isc|dns|dst)/result.h>$%) {
9bb05852fed91ff3913601b7ed8e43e711aa9094David Lawrence unless ($dir eq "isc" && /$nocomment.*isc_result_t/m) {
9bb05852fed91ff3913601b7ed8e43e711aa9094David Lawrence # No {foo}_R_, but it is acceptable to include isc/result.h for
9bb05852fed91ff3913601b7ed8e43e711aa9094David Lawrence # isc_result_t ... but not both isc/result.h and isc/types.h.
9bb05852fed91ff3913601b7ed8e43e711aa9094David Lawrence # The later check will determine isc/result.h to be redundant,
9bb05852fed91ff3913601b7ed8e43e711aa9094David Lawrence # so only the ISC_R_ aspect has to be pointed out.
595babf6279b0f07895c42fd1b74a5f437ccacefDavid Lawrence print "$file has <$dir/result.h> without \U$dir\E_R_\n";
595babf6279b0f07895c42fd1b74a5f437ccacefDavid Lawrence # There is an {foo}_R_; this is a necessary include.
0978cb57f3ef18a63748699a5b1dd607866f6107David Lawrence print "$file includes <$lib/lang.h> but " .
0978cb57f3ef18a63748699a5b1dd607866f6107David Lawrence "has no \U$lib\E_LANG_BEGINDECLS\n";
0978cb57f3ef18a63748699a5b1dd607866f6107David Lawrence print "$file has \U$lib\E_LANG_BEGINDECLS but " .
0978cb57f3ef18a63748699a5b1dd607866f6107David Lawrence "has no \U$lib\E_LANG_ENDDECLS\n";
9bb05852fed91ff3913601b7ed8e43e711aa9094David Lawrence } elsif (! /^$nocomment(?!#define)[a-z].*([a-zA-Z0-9]\()/m) {
0978cb57f3ef18a63748699a5b1dd607866f6107David Lawrence print "$file has <$lib/lang.h> apparently not function declarations\n";
595babf6279b0f07895c42fd1b74a5f437ccacefDavid Lawrence print "$file has <isc/eventclass.h> without ISC_EVENTCLASS_\n";
595babf6279b0f07895c42fd1b74a5f437ccacefDavid Lawrence print "$file has <isc/resultclass.h> without ISC_RESULTCLASS_\n";
595babf6279b0f07895c42fd1b74a5f437ccacefDavid Lawrence print "$file has <$dir/types.h> but apparently no $dir\_*_t uses\n";
595babf6279b0f07895c42fd1b74a5f437ccacefDavid Lawrence } elsif ($dir ne "isc" && m%^#include <isc/types.h>%m) {
595babf6279b0f07895c42fd1b74a5f437ccacefDavid Lawrence print "$file has <$dir/types.h> and redundant <isc/types.h>\n";
595babf6279b0f07895c42fd1b74a5f437ccacefDavid Lawrence # ... otherwise the types.h file is needed for the relevant _t types
595babf6279b0f07895c42fd1b74a5f437ccacefDavid Lawrence # it defines, even if this header file accidentally picks it up by
595babf6279b0f07895c42fd1b74a5f437ccacefDavid Lawrence # including another header that itself included types.h.
595babf6279b0f07895c42fd1b74a5f437ccacefDavid Lawrence # So skip the elision test in any event.
595babf6279b0f07895c42fd1b74a5f437ccacefDavid Lawrence # XXX would be good to test for files that need types.h but don't
595babf6279b0f07895c42fd1b74a5f437ccacefDavid Lawrence # include it.
595babf6279b0f07895c42fd1b74a5f437ccacefDavid Lawrence next if /^$nocomment.*ISC_(TRUE|FALSE|TF)\W/m;
595babf6279b0f07895c42fd1b74a5f437ccacefDavid Lawrence print "$file has <isc/platform.h> but no ISC_PLATFORM_\n";
595babf6279b0f07895c42fd1b74a5f437ccacefDavid Lawrence print "$file has <isc/magic.h> but no ISC_MAGIC_VALID\n";
595babf6279b0f07895c42fd1b74a5f437ccacefDavid Lawrence print "$file elided $elided, compiling\n" if $debug;
0978cb57f3ef18a63748699a5b1dd607866f6107David Lawrence if (compile($file, $tmpfile, $objfile) == 0) {
595babf6279b0f07895c42fd1b74a5f437ccacefDavid Lawrence print "$file does not need $elided\n";
0978cb57f3ef18a63748699a5b1dd607866f6107David Lawrence $includes = "$isc_includes $dns_includes $omapi_includes";
0978cb57f3ef18a63748699a5b1dd607866f6107David Lawrence system("cc $includes -c $source -o $objfile $stderr");