nexmon – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | #!/usr/bin/env perl |
2 | # |
||
3 | # Copyright 2013, William Meier (See AUTHORS file) |
||
4 | # |
||
5 | # Validate hf_... and ei_... usage for a dissector file; |
||
6 | # |
||
7 | # Usage: checkhf.pl [--debug=?] <file or files> |
||
8 | # |
||
9 | # Wireshark - Network traffic analyzer |
||
10 | # By Gerald Combs <gerald@wireshark.org> |
||
11 | # Copyright 1998 Gerald Combs |
||
12 | # |
||
13 | # This program is free software; you can redistribute it and/or |
||
14 | # modify it under the terms of the GNU General Public License |
||
15 | # as published by the Free Software Foundation; either version 2 |
||
16 | # of the License, or (at your option) any later version. |
||
17 | # |
||
18 | # This program is distributed in the hope that it will be useful, |
||
19 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
20 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||
21 | # GNU General Public License for more details. |
||
22 | # |
||
23 | # You should have received a copy of the GNU General Public License |
||
24 | # along with this program; if not, write to the Free Software |
||
25 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
||
26 | # |
||
27 | |||
28 | ## Note: This program is a re-implementation of the |
||
29 | ## original checkhf.pl written and (C) by Joerg Mayer. |
||
30 | ## The overall objective of the new implementation was to reduce |
||
31 | ## the number of false positives which occurred with the |
||
32 | ## original checkhf.pl |
||
33 | ## |
||
34 | ## This program can be used to scan original .c source files or source |
||
35 | ## files which have been passed through a C pre-processor. |
||
36 | ## Operating on pre-processed source files is optimal; There should be |
||
37 | ## minimal false positives. |
||
38 | ## If the .c input is an original source file there may very well be |
||
39 | ## false positives/negatives due to the fact that the hf_... variables & etc |
||
40 | ## may be created via macros. |
||
41 | ## |
||
42 | ## ----- (The following is extracted from the original checkhf.pl with thanks to Joerg) ------- |
||
43 | ## Example: |
||
44 | ## ~/work/wireshark/trunk/epan/dissectors> ../../tools/checkhf.pl packet-afs.c |
||
45 | ## Unused entry: packet-afs.c, hf_afs_ubik_voteend |
||
46 | ## Unused entry: packet-afs.c, hf_afs_ubik_errcode |
||
47 | ## Unused entry: packet-afs.c, hf_afs_ubik_votetype |
||
48 | ## ERROR: NO ARRAY: packet-afs.c, hf_afs_fs_ipaddr |
||
49 | ## |
||
50 | ## or checkhf.pl packet-*.c, which will check all the dissector files. |
||
51 | ## |
||
52 | ## NOTE: This tool currently generates false positives! |
||
53 | ## |
||
54 | ## The "NO ARRAY" messages - if accurate - points to an error that will |
||
55 | ## cause (t|wire)shark to report a DISSECTOR_BUG when a packet containing |
||
56 | ## this particular element is being dissected. |
||
57 | ## |
||
58 | ## The "Unused entry" message indicates the opposite: We define an entry but |
||
59 | ## never use it (e.g., in a proto_...add... function). |
||
60 | ## ------------------------------------------------------------------------------------ |
||
61 | |||
62 | # ------------------------------------------------------------------------------------ |
||
63 | # Main |
||
64 | # |
||
65 | # Logic: |
||
66 | # 1. Clean the input: remove blank lines, comments, quoted strings and code under '#if 0'. |
||
67 | # 2. hf_defs: |
||
68 | # Find (and remove from input) list of hf_... variable |
||
69 | # definitions ('static? g?int hf_... ;') |
||
70 | # 2. hf_array_entries: |
||
71 | # Find (and remove from input) list of hf_... variables |
||
72 | # referenced in the hf[] entries; |
||
73 | # 3. hf_usage: |
||
74 | # From the remaining input, extract list of all strings of form hf_... |
||
75 | # (which may include strings which are not actually valid |
||
76 | # hf_... variable references). |
||
77 | # 4. Checks: |
||
78 | # If entries in hf_defs not in hf_usage then "unused" (for static hf_defs only) |
||
79 | # If entries in hf_defs not in hf_array_entries then "ERROR: NO ARRAY"; |
||
80 | |||
81 | use strict; |
||
82 | use warnings; |
||
83 | |||
84 | use Getopt::Long; |
||
85 | |||
86 | my $help_flag = ''; |
||
87 | my $debug = 0; # default: off; 1=cmt; 2=#if0; 3=hf_defs; 4=hf_array_entries; 5=hfusage (See code) |
||
88 | |||
89 | my $sts = GetOptions( |
||
90 | 'debug=i' => \$debug, |
||
91 | 'help|?' => \$help_flag |
||
92 | ); |
||
93 | if (!$sts || $help_flag || !$ARGV[0]) { |
||
94 | usage(); |
||
95 | } |
||
96 | |||
97 | my $error = 0; |
||
98 | |||
99 | while (my $filename = $ARGV[0]) { |
||
100 | shift; |
||
101 | |||
102 | my ($file_contents); |
||
103 | my (%hf_defs, %hf_static_defs, %hf_array_entries, %hf_usage); |
||
104 | my ($unused_href, $no_array_href); |
||
105 | my (%ei_defs, %ei_static_defs, %ei_array_entries, %ei_usage); |
||
106 | my ($unused_ei, $no_array_ei); |
||
107 | |||
108 | read_file(\$filename, \$file_contents); |
||
109 | |||
110 | remove_comments (\$file_contents, $filename); |
||
111 | remove_blank_lines (\$file_contents, $filename); |
||
112 | remove_quoted_strings(\$file_contents, $filename); |
||
113 | remove_if0_code (\$file_contents, $filename); |
||
114 | |||
115 | find_remove_hf_defs (\$file_contents, $filename, \%hf_defs); |
||
116 | find_remove_hf_array_entries (\$file_contents, $filename, \%hf_array_entries); |
||
117 | find_remove_proto_get_id_hf_assignments(\$file_contents, $filename, \%hf_array_entries); |
||
118 | find_hf_usage (\$file_contents, $filename, \%hf_usage); |
||
119 | |||
120 | find_remove_ei_defs (\$file_contents, $filename, \%ei_defs); |
||
121 | find_remove_ei_array_entries (\$file_contents, $filename, \%ei_array_entries); |
||
122 | find_ei_usage (\$file_contents, $filename, \%ei_usage); |
||
123 | |||
124 | # Tests (See above) |
||
125 | # 1. Are all the static hf_defs and ei_defs entries in hf_usage and ei_usage? |
||
126 | # if not: "Unused entry:" |
||
127 | # |
||
128 | |||
129 | # create a hash containing entries just for the static definitions |
||
130 | @hf_static_defs{grep {$hf_defs{$_} == 0} keys %hf_defs} = (); # All values in the new hash will be undef |
||
131 | @ei_static_defs{grep {$ei_defs{$_} == 0} keys %ei_defs} = (); # All values in the new hash will be undef |
||
132 | |||
133 | $unused_href = diff_hash(\%hf_static_defs, \%hf_usage); |
||
134 | remove_hf_pid_from_unused_if_add_oui_call(\$file_contents, $filename, $unused_href); |
||
135 | |||
136 | $unused_ei = diff_hash(\%ei_static_defs, \%ei_usage); |
||
137 | |||
138 | print_list("Unused href entry: $filename: ", $unused_href); |
||
139 | print_list("Unused ei entry: $filename: ", $unused_ei); |
||
140 | |||
141 | # 2. Are all the hf_defs and ei_ entries (static and global) in [hf|ei]_array_entries ? |
||
142 | # (Note: if a static hf_def or ei is "unused", don't check for same in [hf|ei]_array_entries) |
||
143 | # if not: "ERROR: NO ARRAY" |
||
144 | |||
145 | ## Checking for missing global defs currently gives false positives |
||
146 | ## So: only check static defs for now. |
||
147 | ## $no_array_href = diff_hash(\%hf_defs, \%hf_array_entries); |
||
148 | $no_array_href = diff_hash(\%hf_static_defs, \%hf_array_entries); |
||
149 | $no_array_href = diff_hash($no_array_href, $unused_href); # Remove "unused" hf_... from no_array list |
||
150 | $no_array_ei = diff_hash(\%ei_static_defs, \%ei_array_entries); |
||
151 | $no_array_ei = diff_hash($no_array_ei, $unused_ei); # Remove "unused" ei_... from no_array list |
||
152 | |||
153 | print_list("ERROR: NO ARRAY: $filename: ", $no_array_href); |
||
154 | print_list("ERROR: NO ARRAY: $filename: ", $no_array_ei); |
||
155 | |||
156 | if ((keys %{$no_array_href}) != 0) { |
||
157 | $error += 1; |
||
158 | } |
||
159 | if ((keys %{$no_array_ei}) != 0) { |
||
160 | $error += 1; |
||
161 | } |
||
162 | } |
||
163 | |||
164 | exit (($error == 0) ? 0 : 1); # exit 1 if ERROR |
||
165 | |||
166 | |||
167 | # --------------------------------------------------------------------- |
||
168 | # |
||
169 | sub usage { |
||
170 | print "Usage: $0 [--debug=n] Filename [...]\n"; |
||
171 | exit(1); |
||
172 | } |
||
173 | |||
174 | # --------------------------------------------------------------------- |
||
175 | # action: read contents of a file to specified string |
||
176 | # arg: filename_ref, file_contents_ref |
||
177 | |||
178 | sub read_file { |
||
179 | my ($filename_ref, $file_contents_ref) = @_; |
||
180 | |||
181 | die "No such file: \"${$filename_ref}\"\n" if (! -e ${$filename_ref}); |
||
182 | |||
183 | # delete leading './' |
||
184 | ${$filename_ref} =~ s{ ^ [.] / } {}xmso; |
||
185 | |||
186 | # Read in the file (ouch, but it's easier that way) |
||
187 | open(my $fci, "<:crlf", ${$filename_ref}) || die("Couldn't open ${$filename_ref}"); |
||
188 | |||
189 | ${$file_contents_ref} = do { local( $/ ) ; <$fci> } ; |
||
190 | |||
191 | close($fci); |
||
192 | |||
193 | return; |
||
194 | } |
||
195 | |||
196 | # --------------------------------------------------------------------- |
||
197 | # action: Create a hash containing entries in 'a' that are not in 'b' |
||
198 | # arg: a_href, b_href |
||
199 | # returns: pointer to hash |
||
200 | |||
201 | sub diff_hash { |
||
202 | my ($a_href, $b_href) = @_; |
||
203 | |||
204 | my %diffs; |
||
205 | |||
206 | @diffs{grep {! exists $b_href->{$_}} keys %{$a_href}} = (); # All values in the new hash will be undef |
||
207 | |||
208 | return \%diffs; |
||
209 | } |
||
210 | |||
211 | # --------------------------------------------------------------------- |
||
212 | # action: print a list |
||
213 | # arg: hdr, list_href |
||
214 | |||
215 | sub print_list { |
||
216 | my ($hdr, $list_href) = @_; |
||
217 | |||
218 | print |
||
219 | map {"$hdr$_\n"} |
||
220 | sort |
||
221 | keys %{$list_href}; |
||
222 | |||
223 | return; |
||
224 | } |
||
225 | |||
226 | # ------------ |
||
227 | # action: remove blank lines from input string |
||
228 | # arg: code_ref, filename |
||
229 | |||
230 | sub remove_blank_lines { |
||
231 | my ($code_ref, $filename) = @_; |
||
232 | |||
233 | ${$code_ref} =~ s{ ^ \s* \n ? } {}xmsog; |
||
234 | |||
235 | return; |
||
236 | } |
||
237 | |||
238 | # ------------ |
||
239 | # action: remove comments from input string |
||
240 | # arg: code_ref, filename |
||
241 | |||
242 | sub remove_comments { |
||
243 | my ($code_ref, $filename) = @_; |
||
244 | |||
245 | # The below Regexp is based on one from: |
||
246 | # http://aspn.activestate.com/ASPN/Cookbook/Rx/Recipe/59811 |
||
247 | # It is in the public domain. |
||
248 | # A complicated regex which matches C-style comments. |
||
249 | my $c_comment_regex = qr{ / [*] [^*]* [*]+ (?: [^/*] [^*]* [*]+ )* / }xmso; |
||
250 | |||
251 | ${$code_ref} =~ s{ $c_comment_regex } {}xmsog; |
||
252 | |||
253 | ($debug == 1) && print "==> After Remove Comments: code: [$filename]\n${$code_ref}\n===<\n"; |
||
254 | |||
255 | return; |
||
256 | } |
||
257 | |||
258 | # ------------ |
||
259 | # action: remove quoted strings from input string |
||
260 | # arg: code_ref, filename |
||
261 | |||
262 | sub remove_quoted_strings { |
||
263 | my ($code_ref, $filename) = @_; |
||
264 | |||
265 | # A regex which matches double-quoted strings. |
||
266 | # 's' modifier added so that strings containing a 'line continuation' |
||
267 | # ( \ followed by a new-line) will match. |
||
268 | my $double_quoted_str = qr{ (?: ["] (?: \\. | [^\"\\])* ["]) }xmso; |
||
269 | |||
270 | # A regex which matches single-quoted strings. |
||
271 | my $single_quoted_str = qr{ (?: ['] (?: \\. | [^\'\\])* [']) }xmso; |
||
272 | |||
273 | ${$code_ref} =~ s{ $double_quoted_str | $single_quoted_str } {}xmsog; |
||
274 | |||
275 | ($debug == 1) && print "==> After Remove quoted strings: code: [$filename]\n${$code_ref}\n===<\n"; |
||
276 | |||
277 | return; |
||
278 | } |
||
279 | |||
280 | # ------------- |
||
281 | # action: remove '#if 0'd code from the input string |
||
282 | # args code_ref, filename |
||
283 | # |
||
284 | # Essentially: Use s//patsub/meg to pass each line to patsub. |
||
285 | # patsub monitors #if/#if 0/etc and determines |
||
286 | # if a particular code line should be removed. |
||
287 | # XXX: This is probably pretty inefficient; |
||
288 | # I could imagine using another approach such as converting |
||
289 | # the input string to an array of lines and then making |
||
290 | # a pass through the array deleting lines as needed. |
||
291 | |||
292 | { # block begin |
||
293 | my ($if_lvl, $if0_lvl, $if0); # shared vars |
||
294 | |||
295 | sub remove_if0_code { |
||
296 | my ($code_ref, $filename) = @_; |
||
297 | |||
298 | # First see if any '#if 0' lines which need to be handled |
||
299 | if (${$code_ref} !~ m{ \# \s* if \s+ 0 }xmso ) { |
||
300 | return; |
||
301 | } |
||
302 | |||
303 | my ($preproc_regex) = qr{ |
||
304 | ( # $1 [complete line) |
||
305 | ^ |
||
306 | (?: # non-capturing |
||
307 | \s* \# \s* |
||
308 | (if \s 0| if | else | endif) # $2 (only if #...) |
||
309 | ) ? |
||
310 | [^\n]* |
||
311 | \n ? |
||
312 | ) |
||
313 | }xmso; |
||
314 | |||
315 | ($if_lvl, $if0_lvl, $if0) = (0,0,0); |
||
316 | ${$code_ref} =~ s{ $preproc_regex } { patsub($1,$2) }xmsoeg; |
||
317 | |||
318 | ($debug == 2) && print "==> After Remove if0: code: [$filename]\n${$code_ref}\n===<\n"; |
||
319 | return; |
||
320 | } |
||
321 | |||
322 | sub patsub { |
||
323 | if ($debug == 99) { |
||
324 | print "-->$_[0]\n"; |
||
325 | (defined $_[1]) && print " >$_[1]<\n"; |
||
326 | } |
||
327 | |||
328 | # #if/#if 0/#else/#endif processing |
||
329 | if (defined $_[1]) { |
||
330 | my ($if) = $_[1]; |
||
331 | if ($if eq 'if') { |
||
332 | $if_lvl += 1; |
||
333 | } |
||
334 | elsif ($if eq 'if 0') { |
||
335 | $if_lvl += 1; |
||
336 | if ($if0_lvl == 0) { |
||
337 | $if0_lvl = $if_lvl; |
||
338 | $if0 = 1; # inside #if 0 |
||
339 | } |
||
340 | } |
||
341 | elsif ($if eq 'else') { |
||
342 | if ($if0_lvl == $if_lvl) { |
||
343 | $if0 = 0; |
||
344 | } |
||
345 | } |
||
346 | elsif ($if eq 'endif') { |
||
347 | if ($if0_lvl == $if_lvl) { |
||
348 | $if0 = 0; |
||
349 | $if0_lvl = 0; |
||
350 | } |
||
351 | $if_lvl -= 1; |
||
352 | if ($if_lvl < 0) { |
||
353 | die "patsub: #if/#endif mismatch" |
||
354 | } |
||
355 | } |
||
356 | return $_[0]; # don't remove preprocessor lines themselves |
||
357 | } |
||
358 | |||
359 | # not preprocessor line: See if under #if 0: If so, remove |
||
360 | if ($if0 == 1) { |
||
361 | return ''; # remove |
||
362 | } |
||
363 | return $_[0]; |
||
364 | } |
||
365 | } # block end |
||
366 | |||
367 | # --------------------------------------------------------------------- |
||
368 | # action: Add to hash an entry for each |
||
369 | # 'static? g?int hf_...' definition (including array names) |
||
370 | # in the input string. |
||
371 | # The entry value will be 0 for 'static' definitions and 1 for 'global' definitions; |
||
372 | # Remove each definition found from the input string. |
||
373 | # args: code_ref, filename, hf_defs_href |
||
374 | # returns: ref to the hash |
||
375 | |||
376 | sub find_remove_hf_defs { |
||
377 | my ($code_ref, $filename, $hf_defs_href) = @_; |
||
378 | |||
379 | # Build pattern to match any of the following |
||
380 | # static? g?int hf_foo = -1; |
||
381 | # static? g?int hf_foo[xxx]; |
||
382 | # static? g?int hf_foo[xxx] = { |
||
383 | |||
384 | # p1: 'static? g?int hf_foo' |
||
385 | my $p1_regex = qr{ |
||
386 | ^ |
||
387 | \s* |
||
388 | (static \s+)? |
||
389 | g?int |
||
390 | \s+ |
||
391 | (hf_[a-zA-Z0-9_]+) # hf_.. |
||
392 | }xmso; |
||
393 | |||
394 | # p2a: ' = -1;' |
||
395 | my $p2a_regex = qr{ |
||
396 | \s* = \s* |
||
397 | (?: |
||
398 | - \s* 1 |
||
399 | ) |
||
400 | \s* ; |
||
401 | }xmso; |
||
402 | |||
403 | # p2b: '[xxx];' or '[xxx] = {' |
||
404 | my $p2b_regex = qr/ |
||
405 | \s* \[ [^\]]+ \] \s* |
||
406 | (?: |
||
407 | = \s* [{] | ; |
||
408 | ) |
||
409 | /xmso; |
||
410 | |||
411 | my $hf_def_regex = qr{ $p1_regex (?: $p2a_regex | $p2b_regex ) }xmso; |
||
412 | |||
413 | while (${$code_ref} =~ m{ $hf_def_regex }xmsog) { |
||
414 | #print ">%s< >$2<\n", (defined $1) ? $1 ; ""; |
||
415 | $hf_defs_href->{$2} = (defined $1) ? 0 : 1; # 'static' if $1 is defined. |
||
416 | } |
||
417 | ($debug == 3) && debug_print_hash("VD: $filename", $hf_defs_href); # VariableDefinition |
||
418 | |||
419 | # remove all |
||
420 | ${$code_ref} =~ s{ $hf_def_regex } {}xmsog; |
||
421 | ($debug == 3) && print "==> After remove hf_defs: code: [$filename]\n${$code_ref}\n===<\n"; |
||
422 | |||
423 | return; |
||
424 | } |
||
425 | |||
426 | # --------------------------------------------------------------------- |
||
427 | # action: Add to hash an entry (hf_...) for each hf[] entry. |
||
428 | # Remove each hf[] entries found from the input string. |
||
429 | # args: code_ref, filename, hf_array_entries_href |
||
430 | |||
431 | sub find_remove_hf_array_entries { |
||
432 | my ($code_ref, $filename, $hf_array_entries_href) = @_; |
||
433 | |||
434 | # hf[] entry regex (to extract an hf_index_name and associated field type) |
||
435 | my $hf_array_entry_regex = qr / |
||
436 | [{] |
||
437 | \s* |
||
438 | & \s* ( [a-zA-Z0-9_]+ ) # &hf |
||
439 | (?: |
||
440 | \s* [[] [^]]+ []] # optional array ref |
||
441 | ) ? |
||
442 | \s* , \s* |
||
443 | [{] |
||
444 | [^}]+ |
||
445 | , \s* |
||
446 | (FT_[a-zA-Z0-9_]+) # field type |
||
447 | \s* , |
||
448 | [^}]+ |
||
449 | , \s* |
||
450 | (?: |
||
451 | HFILL | HF_REF_TYPE_NONE |
||
452 | ) |
||
453 | [^}]* |
||
454 | } |
||
455 | [\s,]* |
||
456 | [}] |
||
457 | /xmso; |
||
458 | |||
459 | # find all the hf[] entries (searching ${$code_ref}). |
||
460 | while (${$code_ref} =~ m{ $hf_array_entry_regex }xmsog) { |
||
461 | ($debug == 98) && print "+++ $1 $2\n"; |
||
462 | $hf_array_entries_href->{$1} = undef; |
||
463 | } |
||
464 | |||
465 | ($debug == 4) && debug_print_hash("AE: $filename", $hf_array_entries_href); # ArrayEntry |
||
466 | |||
467 | # now remove all |
||
468 | ${$code_ref} =~ s{ $hf_array_entry_regex } {}xmsog; |
||
469 | ($debug == 4) && print "==> After remove hf_array_entries: code: [$filename]\n${$code_ref}\n===<\n"; |
||
470 | |||
471 | return; |
||
472 | } |
||
473 | |||
474 | # --------------------------------------------------------------------- |
||
475 | # action: Add to hash an entry (hf_...) for each hf_... var |
||
476 | # found in statements of the form: |
||
477 | # 'hf_... = proto_registrar_get_id_byname ...' |
||
478 | # 'hf_... = proto_get_id_by_filtername ...' |
||
479 | # Remove each such statement found from the input string. |
||
480 | # args: code_ref, filename, hf_array_entries_href |
||
481 | |||
482 | sub find_remove_proto_get_id_hf_assignments { |
||
483 | my ($code_ref, $filename, $hf_array_entries_href) = @_; |
||
484 | |||
485 | my $_regex = qr{ ( hf_ [a-zA-Z0-9_]+ ) |
||
486 | \s* = \s* |
||
487 | (?: proto_registrar_get_id_byname | proto_get_id_by_filter_name ) |
||
488 | }xmso; |
||
489 | |||
490 | my @hfvars = ${$code_ref} =~ m{ $_regex }xmsog; |
||
491 | |||
492 | if (@hfvars == 0) { |
||
493 | return; |
||
494 | } |
||
495 | |||
496 | # found: |
||
497 | # Sanity check: hf_vars shouldn't already be in hf_array_entries |
||
498 | if (defined @$hf_array_entries_href{@hfvars}) { |
||
499 | printf "? one or more of [@hfvars] initialized via proto_registrar_get_by_name() also in hf[] ??\n"; |
||
500 | } |
||
501 | |||
502 | # Now: add to hf_array_entries |
||
503 | @$hf_array_entries_href{@hfvars} = (); |
||
504 | |||
505 | ($debug == 4) && debug_print_hash("PR: $filename", $hf_array_entries_href); |
||
506 | |||
507 | # remove from input (so not considered as 'usage') |
||
508 | ${$code_ref} =~ s{ $_regex } {}xmsog; |
||
509 | |||
510 | ($debug == 4) && print "==> After remove proto_registrar_by_name: code: [$filename]\n${$code_ref}\n===<\n"; |
||
511 | |||
512 | return; |
||
513 | } |
||
514 | |||
515 | # --------------------------------------------------------------------- |
||
516 | # action: Add to hash all hf_... strings remaining in input string. |
||
517 | # arga: code_ref, filename, hf_usage_href |
||
518 | # return: ref to hf_usage hash |
||
519 | # |
||
520 | # The hash will include *all* strings of form hf_... |
||
521 | # which are in the input string (even strings which |
||
522 | # aren't actually vars). |
||
523 | # We don't care since we'll be checking only |
||
524 | # known valid vars against these strings. |
||
525 | |||
526 | sub find_hf_usage { |
||
527 | my ($code_ref, $filename, $hf_usage_href) = @_; |
||
528 | |||
529 | my $hf_usage_regex = qr{ |
||
530 | \b ( hf_[a-zA-Z0-9_]+ ) # hf_... |
||
531 | }xmso; |
||
532 | |||
533 | while (${$code_ref} =~ m{ $hf_usage_regex }xmsog) { |
||
534 | #print "$1\n"; |
||
535 | $hf_usage_href->{$1} += 1; |
||
536 | } |
||
537 | |||
538 | ($debug == 5) && debug_print_hash("VU: $filename", $hf_usage_href); # VariableUsage |
||
539 | |||
540 | return; |
||
541 | } |
||
542 | |||
543 | # --------------------------------------------------------------------- |
||
544 | # action: Remove from 'unused' hash an instance of a variable named hf_..._pid |
||
545 | # if the source has a call to llc_add_oui() or ieee802a_add_oui(). |
||
546 | # (This is rather a bit of a hack). |
||
547 | # arga: code_ref, filename, unused_href |
||
548 | |||
549 | sub remove_hf_pid_from_unused_if_add_oui_call { |
||
550 | my ($code_ref, $filename, $unused_href) = @_; |
||
551 | |||
552 | if ((keys %{$unused_href}) == 0) { |
||
553 | return; |
||
554 | } |
||
555 | |||
556 | my @hfvars = grep { m/ ^ hf_ [a-zA-Z0-9_]+ _pid $ /xmso} keys %{$unused_href}; |
||
557 | |||
558 | if ((@hfvars == 0) || (@hfvars > 1)) { |
||
559 | return; # if multiple unused hf_..._pid |
||
560 | } |
||
561 | |||
562 | if (${$code_ref} !~ m{ llc_add_oui | ieee802a_add_oui }xmso) { |
||
563 | return; |
||
564 | } |
||
565 | |||
566 | # hf_...pid unused var && a call to ..._add_oui(); delete entry from unused |
||
567 | # XXX: maybe hf_..._pid should really be added to hfUsed ? |
||
568 | delete @$unused_href{@hfvars}; |
||
569 | |||
570 | return; |
||
571 | } |
||
572 | |||
573 | # --------------------------------------------------------------------- |
||
574 | # action: Add to hash an entry for each |
||
575 | # 'static? expert_field ei_...' definition (including array names) |
||
576 | # in the input string. |
||
577 | # The entry value will be 0 for 'static' definitions and 1 for 'global' definitions; |
||
578 | # Remove each definition found from the input string. |
||
579 | # args: code_ref, filename, hf_defs_href |
||
580 | # returns: ref to the hash |
||
581 | |||
582 | sub find_remove_ei_defs { |
||
583 | my ($code_ref, $filename, $ei_defs_eiref) = @_; |
||
584 | |||
585 | # Build pattern to match any of the following |
||
586 | # static? expert_field ei_foo = -1; |
||
587 | # static? expert_field ei_foo[xxx]; |
||
588 | # static? expert_field ei_foo[xxx] = { |
||
589 | |||
590 | # p1: 'static? expert_field ei_foo' |
||
591 | my $p1_regex = qr{ |
||
592 | ^ |
||
593 | \s* |
||
594 | (static \s+)? |
||
595 | expert_field |
||
596 | \s+ |
||
597 | (ei_[a-zA-Z0-9_]+) # ei_.. |
||
598 | }xmso; |
||
599 | |||
600 | # p2a: ' = EI_INIT;' |
||
601 | my $p2a_regex = qr{ |
||
602 | \s* = \s* |
||
603 | (?: |
||
604 | EI_INIT |
||
605 | ) |
||
606 | \s* ; |
||
607 | }xmso; |
||
608 | |||
609 | # p2b: '[xxx];' or '[xxx] = {' |
||
610 | my $p2b_regex = qr/ |
||
611 | \s* \[ [^\]]+ \] \s* |
||
612 | (?: |
||
613 | = \s* [{] | ; |
||
614 | ) |
||
615 | /xmso; |
||
616 | |||
617 | my $ei_def_regex = qr{ $p1_regex (?: $p2a_regex | $p2b_regex ) }xmso; |
||
618 | |||
619 | while (${$code_ref} =~ m{ $ei_def_regex }xmsog) { |
||
620 | #print ">%s< >$2<\n", (defined $1) ? $1 ; ""; |
||
621 | $ei_defs_eiref->{$2} = (defined $1) ? 0 : 1; # 'static' if $1 is defined. |
||
622 | } |
||
623 | ($debug == 3) && debug_print_hash("VD: $filename", $ei_defs_eiref); # VariableDefinition |
||
624 | |||
625 | # remove all |
||
626 | ${$code_ref} =~ s{ $ei_def_regex } {}xmsog; |
||
627 | ($debug == 3) && print "==> After remove ei_defs: code: [$filename]\n${$code_ref}\n===<\n"; |
||
628 | |||
629 | return; |
||
630 | } |
||
631 | |||
632 | # --------------------------------------------------------------------- |
||
633 | # action: Add to hash an entry (ei_...) for each ei[] entry. |
||
634 | # Remove each ei[] entries found from the input string. |
||
635 | # args: code_ref, filename, ei_array_entries_href |
||
636 | |||
637 | sub find_remove_ei_array_entries { |
||
638 | my ($code_ref, $filename, $ei_array_entries_eiref) = @_; |
||
639 | |||
640 | # ei[] entry regex (to extract an ei_index_name and associated field type) |
||
641 | my $ei_array_entry_regex = qr / |
||
642 | { |
||
643 | \s* |
||
644 | & \s* ( [a-zA-Z0-9_]+ ) # &ei |
||
645 | (?: |
||
646 | \s* [ [^]]+ ] # optional array ref |
||
647 | ) ? |
||
648 | \s* , \s* |
||
649 | { |
||
650 | # \s* "[^"]+" # (filter string has been removed already) |
||
651 | \s* , \s* |
||
652 | PI_[A-Z0-9_]+ # event group |
||
653 | \s* , \s* |
||
654 | PI_[A-Z0-9_]+ # event severity |
||
655 | \s* , |
||
656 | [^,]* # description string (already removed) or NULL |
||
657 | , \s* |
||
658 | EXPFILL |
||
659 | \s* |
||
660 | } |
||
661 | \s* |
||
662 | } |
||
663 | /xs; |
||
664 | |||
665 | # find all the ei[] entries (searching ${$code_ref}). |
||
666 | while (${$code_ref} =~ m{ $ei_array_entry_regex }xsg) { |
||
667 | ($debug == 98) && print "+++ $1\n"; |
||
668 | $ei_array_entries_eiref->{$1} = undef; |
||
669 | } |
||
670 | |||
671 | ($debug == 4) && debug_print_hash("AE: $filename", $ei_array_entries_eiref); # ArrayEntry |
||
672 | |||
673 | # now remove all |
||
674 | ${$code_ref} =~ s{ $ei_array_entry_regex } {}xmsog; |
||
675 | ($debug == 4) && print "==> After remove ei_array_entries: code: [$filename]\n${$code_ref}\n===<\n"; |
||
676 | |||
677 | return; |
||
678 | } |
||
679 | |||
680 | # --------------------------------------------------------------------- |
||
681 | # action: Add to hash all ei_... strings remaining in input string. |
||
682 | # arga: code_ref, filename, ei_usage_eiref |
||
683 | # return: ref to ei_usage hash |
||
684 | # |
||
685 | # The hash will include *all* strings of form ei_... |
||
686 | # which are in the input string (even strings which |
||
687 | # aren't actually vars). |
||
688 | # We don't care since we'll be checking only |
||
689 | # known valid vars against these strings. |
||
690 | |||
691 | sub find_ei_usage { |
||
692 | my ($code_ref, $filename, $ei_usage_eiref) = @_; |
||
693 | |||
694 | my $ei_usage_regex = qr{ |
||
695 | \b ( ei_[a-zA-Z0-9_]+ ) # ei_... |
||
696 | }xmso; |
||
697 | |||
698 | while (${$code_ref} =~ m{ $ei_usage_regex }xmsog) { |
||
699 | #print "$1\n"; |
||
700 | $ei_usage_eiref->{$1} += 1; |
||
701 | } |
||
702 | |||
703 | ($debug == 5) && debug_print_hash("VU: $filename", $ei_usage_eiref); # VariableUsage |
||
704 | |||
705 | return; |
||
706 | } |
||
707 | |||
708 | # --------------------------------------------------------------------- |
||
709 | sub debug_print_hash { |
||
710 | my ($title, $href) = @_; |
||
711 | |||
712 | ##print "==> $title\n"; |
||
713 | for my $k (sort keys %{$href}) { |
||
714 | my $h = defined($href->{$k}) ? $href->{$k} : "undef"; |
||
715 | printf "%-40.40s %5.5s %s\n", $title, $h, $k; |
||
716 | } |
||
717 | } |