summaryrefslogtreecommitdiffstats
path: root/source4/script
diff options
context:
space:
mode:
Diffstat (limited to 'source4/script')
-rwxr-xr-xsource4/script/buildtree.pl40
-rwxr-xr-xsource4/script/depfilter.py53
-rwxr-xr-xsource4/script/extract_allparms.sh2
-rwxr-xr-xsource4/script/find_unused_options.sh37
-rwxr-xr-xsource4/script/minimal_includes.pl171
-rwxr-xr-xsource4/script/mkproto.pl252
-rwxr-xr-xsource4/script/update-proto.pl242
7 files changed, 797 insertions, 0 deletions
diff --git a/source4/script/buildtree.pl b/source4/script/buildtree.pl
new file mode 100755
index 0000000..a40036a
--- /dev/null
+++ b/source4/script/buildtree.pl
@@ -0,0 +1,40 @@
+#! /usr/bin/env perl -w
+ eval 'exec /usr/bin/env perl -S $0 ${1+"$@"}'
+ if 0; #$running_under_some_shell
+
+use strict;
+use File::Find ();
+use File::Path qw(mkpath);
+use Cwd 'abs_path';
+
+# Set the variable $File::Find::dont_use_nlink if you're using AFS,
+# since AFS cheats.
+
+# for the convenience of &wanted calls, including -eval statements:
+use vars qw/*name *dir *prune/;
+*name = *File::Find::name;
+*dir = *File::Find::dir;
+*prune = *File::Find::prune;
+my $builddir = abs_path($ENV{builddir});
+my $srcdir = abs_path($ENV{srcdir});
+sub wanted;
+
+
+
+# Traverse desired filesystems
+File::Find::find({wanted => \&wanted, no_chdir => 1}, $srcdir);
+exit;
+
+
+sub wanted {
+ my ($dev,$ino,$mode,$nlink,$uid,$gid,$newdir);
+
+ if ((($dev,$ino,$mode,$nlink,$uid,$gid) = lstat($_)) &&
+ (-d _) && (($newdir = abs_path($_)) !~ /$builddir/))
+ {
+ $newdir =~ s!$srcdir!$builddir!;
+ mkpath($newdir);
+ print("Creating $newdir\n");
+ }
+}
+
diff --git a/source4/script/depfilter.py b/source4/script/depfilter.py
new file mode 100755
index 0000000..ee2ce9d
--- /dev/null
+++ b/source4/script/depfilter.py
@@ -0,0 +1,53 @@
+#!/usr/bin/env python3
+#
+# Filter out arcs in a dotty graph that are at or below a certain
+# node. This is useful for visualising parts of the dependency graph.
+#
+
+# Command line stuff
+
+import sys
+import re
+
+if len(sys.argv) != 2:
+ print('Usage: depfilter.py NODE')
+ sys.exit(1)
+
+top = sys.argv[1]
+
+# Read in dot file
+
+lines = sys.stdin.readlines()
+
+graph = {}
+
+for arc in lines[1:-1]:
+ match = re.search('"(.*)" -> "(.*)"', arc)
+ n1, n2 = match.group(1), match.group(2)
+ if n1 not in graph:
+ graph[n1] = []
+ graph[n1].append(n2)
+
+# Create subset of 'graph' rooted at 'top'
+
+subgraph = {}
+
+
+def add_deps(node):
+ if node in graph and node not in subgraph:
+ subgraph[node] = graph[node]
+ for n in graph[node]:
+ add_deps(n)
+
+
+add_deps(top)
+
+# Generate output
+
+print(lines[0], end=' ')
+
+for key, value in subgraph.items():
+ for n in value:
+ print('\t"%s" -> "%s"' % (key, n))
+
+print(lines[-1], end=' ')
diff --git a/source4/script/extract_allparms.sh b/source4/script/extract_allparms.sh
new file mode 100755
index 0000000..f16068b
--- /dev/null
+++ b/source4/script/extract_allparms.sh
@@ -0,0 +1,2 @@
+#!/bin/sh
+grep '{".*P_[GL]' param/loadparm.c | sed -e 's/&.*$//g' -e 's/",.*P_LOCAL.*$/ S/' -e 's/",.*P_GLOBAL.*$/ G/' -e 's/^ .*{"//g' | sort -f
diff --git a/source4/script/find_unused_options.sh b/source4/script/find_unused_options.sh
new file mode 100755
index 0000000..36e9771
--- /dev/null
+++ b/source4/script/find_unused_options.sh
@@ -0,0 +1,37 @@
+#!/bin/sh
+#
+# this script finds unused lp_*() functions
+#
+# use it like this:
+#
+# user@host:~/samba/source>./script/find_unused_options.sh
+#
+
+LIST_GLOBAL=$(grep '^FN_GLOBAL' param/loadparm.c | sed -e's/^FN_GLOBAL.*(\(.*\).*,.*\(&Globals\..*\)).*/\1:\2/')
+
+LIST_LOCAL=$(grep '^FN_LOCAL' param/loadparm.c | sed -e's/^FN_LOCAL.*(\(.*\).*,[ ]*\(.*\)).*/\1:\2/')
+
+CFILES=$(find . -name "*.c")
+
+for i in $LIST_GLOBAL; do
+ key=$(echo $i | cut -d ':' -f1)
+ val=$(echo $i | cut -d ':' -f2)
+
+ found=$(grep "$key[ ]*()" $CFILES)
+ if test -z "$found"; then
+ echo "Not Used Global: $key() -> $val"
+ fi
+done
+
+for i in $LIST_LOCAL; do
+ key=$(echo $i | cut -d ':' -f1)
+ val=$(echo $i | cut -d ':' -f2)
+
+ found=$(grep "$key[ ]*(" $CFILES)
+
+ if test -z "$found"; then
+ echo "Not Used LOCAL: $key() -> $val"
+ fi
+done
+
+echo "# do a 'make clean;make everything' before removing anything!"
diff --git a/source4/script/minimal_includes.pl b/source4/script/minimal_includes.pl
new file mode 100755
index 0000000..4203d00
--- /dev/null
+++ b/source4/script/minimal_includes.pl
@@ -0,0 +1,171 @@
+#!/usr/bin/perl -w
+# find a list of #include lines in C code that might not be needed
+# usually called with something like this:
+# minimal_includes.pl `find . -name "*.c"`
+# Andrew Tridgell <tridge@samba.org>
+
+use strict;
+use Data::Dumper;
+use Getopt::Long;
+
+my $opt_help = 0;
+my $opt_remove = 0;
+my $opt_skip_system = 0;
+my $opt_waf = 0;
+
+#####################################################################
+# write a string into a file
+sub FileSave($$)
+{
+ my($filename) = shift;
+ my($v) = shift;
+ local(*FILE);
+ open(FILE, ">$filename") || die "can't open $filename";
+ print FILE $v;
+ close(FILE);
+}
+
+sub load_lines($)
+{
+ my $fname = shift;
+ my @lines = split(/^/m, `cat $fname`);
+ return @lines;
+}
+
+sub save_lines($$)
+{
+ my $fname = shift;
+ my $lines = shift;
+ my $data = join('', @{$lines});
+ FileSave($fname, $data);
+}
+
+sub test_compile($)
+{
+ my $fname = shift;
+ my $obj;
+ if ($opt_waf) {
+ my $ret = `../buildtools/bin/waf $fname 2>&1`;
+ return $ret
+ }
+ if ($fname =~ s/(.*)\..*$/$1.o/) {
+ $obj = "$1.o";
+ } else {
+ return "NOT A C FILE";
+ }
+ unlink($obj);
+ my $ret = `make $obj 2>&1`;
+ if (!unlink("$obj")) {
+ return "COMPILE FAILED";
+ }
+ return $ret;
+}
+
+sub test_include($$$$)
+{
+ my $fname = shift;
+ my $lines = shift;
+ my $i = shift;
+ my $original = shift;
+ my $line = $lines->[$i];
+ my $testfname;
+
+ $lines->[$i] = "";
+
+ my $mname = $fname . ".misaved";
+
+ unlink($mname);
+ rename($fname, $mname) || die "failed to rename $fname";
+ save_lines($fname, $lines);
+
+ my $out = test_compile($fname);
+
+ if ($out eq $original) {
+ if ($opt_remove) {
+ if ($opt_skip_system &&
+ $line =~ /system\//) {
+ print "$fname: not removing system include $line\n";
+ } else {
+ print "$fname: removing $line\n";
+ unlink($mname);
+ return;
+ }
+ } else {
+ print "$fname: might be able to remove $line\n";
+ }
+ }
+
+ $lines->[$i] = $line;
+ rename($mname, $fname) || die "failed to restore $fname";
+}
+
+sub process_file($)
+{
+ my $fname = shift;
+ my @lines = load_lines($fname);
+ my $num_lines = $#lines;
+
+ my $original = test_compile($fname);
+
+ if ($original eq "COMPILE FAILED") {
+ print "Failed to compile $fname\n";
+ return;
+ }
+
+ print "Processing $fname (with $num_lines lines)\n";
+
+ my $if_level = 0;
+
+ for (my $i=0;$i<=$num_lines;$i++) {
+ my $line = $lines[$i];
+ if ($line =~ /^\#\s*if/) {
+ $if_level++;
+ }
+ if ($line =~ /^\#\s*endif/) {
+ $if_level--;
+ }
+ if ($if_level == 0 &&
+ $line =~ /^\#\s*include/ &&
+ !($line =~ /needed/)) {
+ test_include($fname, \@lines, $i, $original);
+ }
+ }
+}
+
+
+#########################################
+# display help text
+sub ShowHelp()
+{
+ print "
+ minimise includes
+ Copyright (C) tridge\@samba.org
+
+ Usage: minimal_includes.pl [options] <C files....>
+
+ Options:
+ --help show help
+ --remove remove includes, don't just list them
+ --skip-system don't remove system/ includes
+ --waf use waf target conventions
+";
+}
+
+
+# main program
+GetOptions (
+ 'h|help|?' => \$opt_help,
+ 'remove' => \$opt_remove,
+ 'skip-system' => \$opt_skip_system,
+ 'waf' => \$opt_waf,
+ );
+
+if ($opt_help) {
+ ShowHelp();
+ exit(0);
+}
+
+for (my $i=0;$i<=$#ARGV;$i++) {
+ my $fname = $ARGV[$i];
+ process_file($fname);
+}
diff --git a/source4/script/mkproto.pl b/source4/script/mkproto.pl
new file mode 100755
index 0000000..2c3ebac
--- /dev/null
+++ b/source4/script/mkproto.pl
@@ -0,0 +1,252 @@
+#!/usr/bin/perl
+# Simple script for generating prototypes for C functions
+# Written by Jelmer Vernooij
+# based on the original mkproto.sh by Andrew Tridgell
+
+use strict;
+
+# don't use warnings module as it is not portable enough
+# use warnings;
+
+use Getopt::Long;
+use File::Basename;
+use File::Path;
+
+#####################################################################
+# read a file into a string
+
+my $public_file = undef;
+my $private_file = undef;
+my $all_file = undef;
+my $public_define = undef;
+my $private_define = undef;
+my $_public = "";
+my $_private = "";
+my $public_data = \$_public;
+my $private_data = \$_private;
+my $builddir = ".";
+my $srcdir = ".";
+
+sub public($)
+{
+ my ($d) = @_;
+ $$public_data .= $d;
+}
+
+sub private($)
+{
+ my ($d) = @_;
+ $$private_data .= $d;
+}
+
+sub usage()
+{
+ print "Usage: mkproto.pl [options] [c files]\n";
+ print "OPTIONS:\n";
+ print " --public=FILE Write prototypes for public functions to FILE\n";
+ print " --private=FILE Write prototypes for private functions to FILE\n";
+ print " --define=DEF Use DEF to check whether header was already included\n";
+ print " --public-define=DEF Same as --define, but just for public header\n";
+ print " --private-define=DEF Same as --define, but just for private header\n";
+ print " --srcdir=path Read files relative to this directory\n";
+ print " --builddir=path Write file relative to this directory\n";
+ print " --help Print this help message\n\n";
+ exit 0;
+}
+
+GetOptions(
+ 'public=s' => sub { my ($f,$v) = @_; $public_file = $v; },
+ 'all=s' => sub { my ($f,$v) = @_; $public_file = $v; $private_file = $v; },
+ 'private=s' => sub { my ($f,$v) = @_; $private_file = $v; },
+ 'define=s' => sub {
+ my ($f,$v) = @_;
+ $public_define = $v;
+ $private_define = "$v\_PRIVATE";
+ },
+ 'public-define=s' => \$public_define,
+ 'private-define=s' => \$private_define,
+ 'srcdir=s' => sub { my ($f,$v) = @_; $srcdir = $v; },
+ 'builddir=s' => sub { my ($f,$v) = @_; $builddir = $v; },
+ 'help' => \&usage
+) or exit(1);
+
+sub normalize_define($$)
+{
+ my ($define, $file) = @_;
+
+ if (not defined($define) and defined($file)) {
+ $define = "__" . uc($file) . "__";
+ $define =~ tr{./}{__};
+ $define =~ tr{\-}{_};
+ } elsif (not defined($define)) {
+ $define = '_PROTO_H_';
+ }
+
+ return $define;
+}
+
+$public_define = normalize_define($public_define, $public_file);
+$private_define = normalize_define($private_define, $private_file);
+
+if ((defined($private_file) and defined($public_file) and ($private_file eq $public_file)) or
+ (not defined($private_file) and not defined($public_file))) {
+ $private_data = $public_data;
+}
+
+sub file_load($)
+{
+ my($filename) = @_;
+ local(*INPUTFILE);
+ open(INPUTFILE, $filename) or return undef;
+ my($saved_delim) = $/;
+ undef $/;
+ my($data) = <INPUTFILE>;
+ close(INPUTFILE);
+ $/ = $saved_delim;
+ return $data;
+}
+
+sub print_header($$)
+{
+ my ($file, $header_name) = @_;
+ $file->("#ifndef $header_name\n");
+ $file->("#define $header_name\n\n");
+ $file->("#undef _PRINTF_ATTRIBUTE\n");
+ $file->("#define _PRINTF_ATTRIBUTE(a1, a2) PRINTF_ATTRIBUTE(a1, a2)\n");
+ $file->("/* This file was automatically generated by mkproto.pl. DO NOT EDIT */\n\n");
+}
+
+sub print_footer($$)
+{
+ my ($file, $header_name) = @_;
+ $file->("#undef _PRINTF_ATTRIBUTE\n");
+ $file->("#define _PRINTF_ATTRIBUTE(a1, a2)\n");
+ $file->("\n#endif /* $header_name */\n\n");
+}
+
+sub process_file($$$)
+{
+ my ($public_file, $private_file, $filename) = @_;
+
+ $filename =~ s/\.o$/\.c/g;
+
+ if ($filename =~ /^\//) {
+ open(FH, "<$filename") or die("Failed to open $filename");
+ } elsif (!open(FH, "< $builddir/$filename")) {
+ open(FH, "< $srcdir/$filename") || die "Failed to open $filename";
+ }
+
+ $private_file->("\n/* The following definitions come from $filename */\n\n");
+
+ my $comment = undef;
+ my $incomment = 0;
+ while (my $line = <FH>) {
+ my $target = \&private;
+ my $is_public = 0;
+
+ if ($line =~ /^\/\*\*/) {
+ $comment = "";
+ $incomment = 1;
+ }
+
+ if ($incomment) {
+ $comment .= $line;
+ if ($line =~ /\*\//) {
+ $incomment = 0;
+ }
+ }
+
+ # these are ordered for maximum speed
+ next if ($line =~ /^\s/);
+
+ next unless ($line =~ /\(/);
+
+ next if ($line =~ /^\/|[;]/);
+
+ if ($line =~ /^FN_/) {
+ next;
+ }
+
+ if ($line =~ /^_PUBLIC_[\t ]/) {
+ $target = \&public;
+ $is_public = 1;
+ }
+
+ next unless ( $is_public || $line =~ /
+ ^(_DEPRECATED_ |_NORETURN_ |_WARN_UNUSED_RESULT_ |_PURE_ )*(
+ void|bool|int|struct|char|const|\w+_[tT]\s|uint|unsigned|long|NTSTATUS|
+ ADS_STATUS|enum\s.*\(|DATA_BLOB|WERROR|XFILE|FILE|DIR|
+ double|TDB_CONTEXT|TDB_DATA|TALLOC_CTX|NTTIME|FN_|init_module|
+ GtkWidget|GType|smb_ucs2_t|krb5_error_code|NET_API_STATUS)
+ /xo);
+
+ next if ($line =~ /^int\s*main/);
+
+ $target->("\n$comment") if (defined($comment)); $comment = undef;
+
+ if ( $line =~ /\(.*\)\s*$/o ) {
+ chomp $line;
+ $target->("$line;\n");
+ next;
+ }
+
+ $target->($line);
+
+ while ($line = <FH>) {
+ if ($line =~ /\)\s*$/o) {
+ chomp $line;
+ $target->("$line;\n");
+ last;
+ }
+ $target->($line);
+ }
+ }
+
+ close(FH);
+}
+
+
+print_header(\&public, $public_define);
+if (defined($private_file) and defined($public_file) and $public_file ne $private_file) {
+ print_header(\&private, $private_define);
+
+ private("/* this file contains prototypes for functions that " .
+ "are private \n * to this subsystem or library. These functions " .
+ "should not be \n * used outside this particular subsystem! */\n\n");
+
+ public("/* this file contains prototypes for functions that " .
+ "are part of \n * the public API of this subsystem or library. */\n\n");
+
+}
+
+public("#ifndef _PUBLIC_\n#define _PUBLIC_\n#endif\n\n");
+public("#ifndef _PURE_\n#define _PURE_\n#endif\n\n");
+public("#ifndef _NORETURN_\n#define _NORETURN_\n#endif\n\n");
+public("#ifndef _DEPRECATED_\n#define _DEPRECATED_\n#endif\n\n");
+public("#ifndef _WARN_UNUSED_RESULT_\n#define _WARN_UNUSED_RESULT_\n#endif\n\n");
+
+process_file(\&public, \&private, $_) foreach (@ARGV);
+print_footer(\&public, $public_define);
+if (defined($private_file) and $public_file ne $private_file) {
+ print_footer(\&private, $private_define);
+}
+
+if (not defined($public_file)) {
+ print STDOUT $$public_data;
+}
+
+if (not defined($private_file) and defined($public_file)) {
+ print STDOUT $$private_data;
+}
+
+mkpath(dirname($public_file), 0, 0755);
+open(PUBLIC, ">$public_file") or die("Can't open `$public_file': $!");
+print PUBLIC "$$public_data";
+close(PUBLIC);
+
+if (defined($private_file) and $public_file ne $private_file) {
+ mkpath(dirname($private_file), 0, 0755);
+ open(PRIVATE, ">$private_file") or die("Can't open `$private_file': $!");
+ print PRIVATE "$$private_data";
+ close(PRIVATE);
+}
diff --git a/source4/script/update-proto.pl b/source4/script/update-proto.pl
new file mode 100755
index 0000000..c130650
--- /dev/null
+++ b/source4/script/update-proto.pl
@@ -0,0 +1,242 @@
+#!/usr/bin/perl
+# Simple script for updating the prototypes in a C header file
+#
+# Copyright (C) 2006 Jelmer Vernooij <jelmer@samba.org>
+# Published under the GNU GPL
+
+use strict;
+use warnings;
+use Getopt::Long;
+
+=head1 NAME
+
+update-proto - automatically update prototypes in header files
+
+=head1 SYNOPSIS
+
+update-proto [OPTIONS] <HEADER> <C-FILE>...
+
+update-proto [OPTIONS] <HEADER>
+
+=head1 DESCRIPTION
+
+Update-proto makes sure the prototypes in a C header file are current
+by comparing the existing prototypes in a header with the function definition
+in the source file. It aims to keep the diff between the original header
+and generated one as small as possible.
+
+New prototypes are inserted before any line that contains the following comment:
+
+/* New prototypes are inserted above this line */
+
+It will automatically parse C files after it encounters a line that contains:
+
+/* The following definitions come from FILE */
+
+When two or more prototypes exist for a function, only the first one
+will be kept.
+
+=head1 OPTIONS
+
+=over 4
+
+=item I<--verbose|-v>
+
+Increase verbosity. Currently only two levels of verbosity are used.
+
+=item I<--help>
+
+Show list of options
+
+=back
+
+=head1 BUGS
+
+Strange complex functions are not recognized. In particular those
+created by macros or returning (without typedef) function pointers.
+
+=head1 LICENSE
+
+update-proto is licensed under the GNU General Public License L<http://www.gnu.org/licenses/gpl.html>.
+
+=head1 AUTHOR
+
+update-proto was written by Jelmer Vernooij L<jelmer@samba.org>.
+
+=cut
+
+sub Usage()
+{
+ print "Usage: update-proto.pl [OPTIONS] <HEADER> <C-FILE>...\n";
+ exit 1;
+}
+
+sub Help()
+{
+ print "Usage: update-proto.pl [OPTIONS] <HEADER> <C-FILE>...\n";
+ print "Options:\n";
+ print " --help Show this help message\n";
+ print " --verbose Write changes made to standard error\n\n";
+ exit 0;
+}
+
+my %new_protos = ();
+
+my $verbose = 0;
+
+GetOptions(
+ 'help|h' => \&Help,
+ 'v|verbose' => sub { $verbose += 1; }
+) or Usage();
+
+sub count($$)
+{
+ my ($t, $s) = @_;
+ my $count = 0;
+ while($s =~ s/^(.)//) { $count++ if $1 eq $t; }
+ return $count;
+}
+
+my $header = shift @ARGV;
+
+sub process_file($)
+{
+ my $file = shift;
+ open (IN, "<$file");
+ while (my $line = <IN>) {
+ $_ = $line;
+ next if /^\s/;
+ next unless /\(/;
+ next if /^\/|[;]|^#|}|^\s*static/;
+ s/\/\*(.*?)\*\///g;
+ my $public = s/_PUBLIC_//g;
+ s/_PRINTF_ATTRIBUTE\([^)]+\)//g;
+ next unless /^(struct\s+\w+|union\s+\w+|\w+)\s+\**\s*(\w+)\s*\((.*)$/;
+
+ my $name = $2;
+
+ next if ($name eq "main");
+
+ # Read continuation lines if any
+ my $prn = 1 + count("(", $3) - count(")", $3);
+
+ while ($prn) {
+ my $l = <IN>;
+ $l or die("EOF while parsing function prototype");
+ $line .= $l;
+ $prn += count("(", $l) - count(")", $l);
+ }
+
+ $line =~ s/\n$//;
+
+ # Strip off possible start of function
+ $line =~ s/{\s*$//g;
+
+ $new_protos{$name} = "$line;";
+ }
+ close(IN);
+}
+
+process_file($_) foreach (@ARGV);
+
+my $added = 0;
+my $modified = 0;
+my $deleted = 0;
+my $kept = 0;
+
+sub insert_new_protos()
+{
+ foreach (keys %new_protos) {
+ print "$new_protos{$_}\n";
+ print STDERR "Inserted prototype for `$_'\n" if ($verbose);
+ $added+=1;
+ }
+ %new_protos = ();
+}
+
+my $blankline_due = 0;
+
+open (HDR, "<$header");
+while (my $line = <HDR>) {
+ if ($line eq "\n") {
+ $blankline_due = 1;
+ $line = <HDR>;
+ }
+
+ # Recognize C files that prototypes came from
+ if ($line =~ /\/\* The following definitions come from (.*) \*\//) {
+ insert_new_protos();
+ if ($blankline_due) {
+ print "\n";
+ $blankline_due = 0;
+ }
+ process_file($1);
+ print "$line";
+ next;
+ }
+
+ if ($blankline_due) {
+ print "\n";
+ $blankline_due = 0;
+ }
+
+ # Insert prototypes that weren't in the header before
+ if ($line =~ /\/\* New prototypes are inserted above this line.*\*\/\s*/) {
+ insert_new_protos();
+ print "$line\n";
+ next;
+ }
+
+ if ($line =~ /^\s*typedef |^\#|^\s*static/) {
+ print "$line";
+ next;
+ }
+
+ $_ = $line;
+ s/\/\*(.*?)\*\///g;
+ my $public = s/_PUBLIC_//g;
+ s/_PRINTF_ATTRIBUTE\([^)]+\)//g;
+ unless (/^(struct\s+\w+|union\s+\w+|\w+)\s+\**\s*(\w+)\s*\((.*)$/) {
+ print "$line";
+ next;
+ }
+
+ # Read continuation lines if any
+ my $prn = 1 + count("(", $3) - count(")", $3);
+
+ while ($prn) {
+ my $l = <HDR>;
+ $l or die("EOF while parsing function prototype");
+ $line .= $l;
+ $prn += count("(", $l) - count(")", $l);
+ }
+
+ my $name = $2;
+
+ # This prototype is for a function that was removed
+ unless (defined($new_protos{$name})) {
+ $deleted+=1;
+ print STDERR "Removed prototype for `$name'\n" if ($verbose);
+ next;
+ }
+
+ my $nline = $line;
+ chop($nline);
+
+ if ($new_protos{$name} ne $nline) {
+ $modified+=1;
+ print STDERR "Updated prototype for `$name'\n" if ($verbose);
+ print "$new_protos{$name}\n";
+ } else {
+ $kept+=1;
+ print STDERR "Prototype for `$name' didn't change\n" if ($verbose > 1);
+ print "$line";
+ }
+
+ delete $new_protos{$name};
+}
+close(HDR);
+
+print STDERR "$added added, $modified modified, $deleted deleted, $kept unchanged.\n";
+
+1;