From Martin Peylo (bug 2507):
[metze/wireshark/wip.git] / tools / checkhf.pl
1 #!/usr/bin/perl -w
2
3 my $debug = 0;
4 # 0: off
5 # 1: specific debug
6 # 2: full debug
7
8 #
9 # find unbalanced hf_ variables: Compare hf_ variable usage with the hf_ variables
10 #  declared in the hf_register_info array.
11 #
12 # Usage: checkhf.pl <file or files>
13
14 # $Id$
15
16 #
17 # Copyright 2005 Joerg Mayer (see AUTHORS file)
18 #
19 # Wireshark - Network traffic analyzer
20 # By Gerald Combs <gerald@wireshark.org>
21 # Copyright 1998 Gerald Combs
22 #
23 # This program is free software; you can redistribute it and/or
24 # modify it under the terms of the GNU General Public License
25 # as published by the Free Software Foundation; either version 2
26 # of the License, or (at your option) any later version.
27 #
28 # This program is distributed in the hope that it will be useful,
29 # but WITHOUT ANY WARRANTY; without even the implied warranty of
30 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
31 # GNU General Public License for more details.
32 #
33 # You should have received a copy of the GNU General Public License
34 # along with this program; if not, write to the Free Software
35 # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
36
37 #
38 # Example:
39 # ~/work/wireshark/trunk/epan/dissectors> ../../tools/checkhf.pl packet-afs.c
40 # Unused entry: packet-afs.c, hf_afs_ubik_voteend
41 # Unused entry: packet-afs.c, hf_afs_ubik_errcode
42 # Unused entry: packet-afs.c, hf_afs_ubik_votetype
43 # NO ARRAY: packet-afs.c, hf_afs_fs_ipaddr
44 #
45 # or checkhf.pl packet-*.c, which will check all the dissector files.
46 #
47 # NOTE: This tool currently generates false positives!
48 #
49 # The "NO ARRAY" messages - if accurate - point to an error that will
50 # cause (t)(wire)shark to terminate with an assertion when a packet containing
51 # this particular element is being dissected.
52 #
53 # The "Unused entry" message indicates the opposite: 
54
55 use strict;
56
57 my $D;
58
59 my %elements;
60 my $element;
61 my %skip;
62
63 my $state;
64 my $newstate;
65 # "s_unknown",
66 # "s_declared",
67 # "s_used",
68 # "s_array",
69 # "s_usedarray",
70 # "s_error"
71
72 my $type;
73 # "t_declaration";
74 # "t_usage";
75 # "t_array";
76
77 my $restofline;
78 my $currfile = "";
79
80 my $comment = 0;
81 my $brace = 0;
82
83 sub printprevfile {
84         my $state;
85
86         foreach $element (keys %elements) {
87                 $state = $elements{$element};
88                 $debug>=2 && print "$currfile, $element: PRINT $state\n";
89                 if ($state eq "s_usedarray") {
90                         # Everything is fine
91                 } elsif ($state eq "s_used") {
92                         print "NO ARRAY: $currfile, $element\n"
93                 } elsif ($state eq "s_array") {
94                         print "Unused entry: $currfile, $element\n"
95                 } elsif ($state eq "s_declared") {
96                         print "Declared only entry: $currfile, $element\n"
97                 } elsif ($state eq "s_unknown") {
98                         print "UNKNOWN: $currfile, $element\n"
99                 } else {
100                         die "Impossible: State $state for $currfile, $element\n";
101                 }
102         }
103 }
104
105 while (<>) {
106         if ($currfile !~ /$ARGV/) {
107                 &printprevfile();
108                 # New file - reset array and state
109                 $currfile = $ARGV;
110                 %elements = ( );
111                 %skip = ( "hf_register_info" => 1 );
112                 $state = "s_unknown";
113         }
114         # opening then closing comment
115         if (/(.*?)\/\*.*\*\/(.*)/) {
116                 $comment = 0;
117                 $_ = "$1$2";
118         # closing then opening comment
119         } elsif (/.*?\*\/(.*?)\/\*/) {
120                 $comment = 1;
121                 $_ = "$1";
122         # opening comment
123         } elsif (/(.*?)\/\*/) {
124                 $comment = 1;
125                 $_ = "$1";
126         # closing comment
127         } elsif (/\*\/(.*?)/) {
128                 $comment = 0;
129                 $_ = "$1";
130         } elsif ($comment == 1) {
131                 next;
132         }
133         # unhandled: more than one complete comment per line
134
135         chomp;
136         if ($debug) {
137                 $D = " ($_)";
138         } else {
139                 $D = "";
140         }
141
142         # Read input
143         if (/static\s+.*int\s+(hf_\w*)\s*=\s*-1\s*;/) {
144                 $element = $1;
145                 $type = "t_declaration";
146                 # ignore: declarations without any use are detected by the compiler
147                 next;
148         # Skip function parameter declarations with hf_ names
149         } elsif (/(int\s+?|int\s*?\*\s*?|header_field_info\s+?|header_field_info\s*?\*\s*?|hf_register_info\s+?|hf_register_info\s*?\*\s*?|->\s*?)(hf_\w*)\W(.*)/) {
150                 $element = $2;
151                 $restofline = $3;
152                 $debug && print "Setting skip for $element$D\n";
153                 $skip{$element} = 1;
154                 # Handle functions with multiple hf_ parameters
155                 while ($restofline =~ /(int\s+?|int\s*?\*\s*?|header_field_info\s+?|header_field_info\s*?\*\s*?|hf_register_info\s+?|hf_register_info\s*?\*\s*?|->\s*?)(hf_\w*)\W(.*)/) {
156                         $element = $2;
157                         $restofline = $3;
158                         $debug && print "Setting skip for $element$D\n";
159                         $skip{$element} = 1;
160                 }
161                 next;
162         } elsif ($brace == 1 && /^\s*?&\s*?(hf_\w*)\W+/) {
163                 $element = $1;
164                 $type = "t_array";
165         } elsif (/^\s*\{\s*?&\s*?(hf_\w*)\W+/) {
166                 $element = $1;
167                 $type = "t_array";
168         # Order matters: catch all remaining hf_ lines
169         } elsif (/\W(hf_\w*)\W/) {
170                 $element = $1;
171                 next if ($skip{$element});
172                 $type = "t_usage";
173         } else {
174                 # current line is not relevant
175                 next;
176         }
177         # Line with only a {
178         if (/^\s+\{\s*$/) {
179                 $brace = 1;
180                 next;
181         } else {
182                 $brace = 0;
183         }
184
185         # Get current state
186         if (!defined($elements{$element})) {
187                 $state = "s_unknown";
188         } else {
189                 $state = $elements{$element};
190         }
191
192         # current state + input ==> new state
193         # we currently ignore t_declaration
194         if ($state eq "s_error") {
195                 $newstate = $state;
196         } elsif ($state eq "s_unknown" && $type eq "t_usage") {
197                         $newstate = "s_used";
198         } elsif ($state eq "s_unknown" && $type eq "t_array") {
199                         $newstate = "s_array";
200         } elsif ($state eq "s_used" && $type eq "t_array") {
201                         $newstate = "s_usedarray";
202         } elsif ($state eq "s_array" && $type eq "t_usage") {
203                         $newstate = "s_usedarray";
204         } else {
205                 $newstate = $state;
206         }
207         $elements{$element} = $newstate;
208         $debug>=2 && print "$currfile, $element: SET $state + $type => $newstate$D\n";
209 }
210 &printprevfile();
211
212 exit 0;
213
214 __END__