summaryrefslogtreecommitdiffstats
path: root/source4/script/update-proto.pl
diff options
context:
space:
mode:
Diffstat (limited to '')
-rwxr-xr-xsource4/script/update-proto.pl242
1 files changed, 242 insertions, 0 deletions
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;