regen pidl all: rm epan/dissectors/pidl/*-stamp; pushd epan/dissectors/pidl/ && make...
[wireshark-sm.git] / tools / convert_expert_add_info_format.pl
blob0b0ddd3281ccaef25c87abcb94aeec5574e78d96
1 #!/usr/bin/env perl
3 # Copyright 2013 Michael Mann (see AUTHORS file)
5 # A program to help convert the "old" expert_add_info_format API calls into filterable "items" that
6 # use the other expert API calls. The program requires 2 passes. "Pass 1" (generate) collects
7 # the eligible expert_add_info_format calls and outputs the necessary data into a delimited
8 # file. "Pass 2" (fix-all) takes the data from the delimited file and replaces the
9 # expert_add_info_format calls with filterable "expert info" calls as well as
10 # generating a separate files for the ei variable declarations and array data.
11 # The ei "file" can be copy/pasted into the dissector where appropriate
13 # Note that the output from "Pass 1" won't always be a perfect conversion for "Pass 2", so
14 # "human interaction" is needed as an intermediary to verify and update the delimited file
15 # before "Pass 2" is done.
17 # Delimited file field format:
18 # <convert expert_add_info_format_call[1-4]><add ei variable[0|1]><ei var><[GROUP]><[SEVERITY]><[FIELDNAME]><[EXPERTABBREV]>
19 # <pinfo var><proto_item var><tvb var><offset><length><params>
21 # convert proto_tree_add_text_call enumerations:
22 # 1 - expert_add_info
23 # 2 - expert_add_info_format
24 # 3 - proto_tree_add_expert
25 # 4 - proto_tree_add_expert_format
27 # Usage: convert_expert_add_info_format.pl action=<generate|fix-all> <file or files>
29 # Based off of convert_proto_tree_add_text.pl
31 # Wireshark - Network traffic analyzer
32 # By Gerald Combs <gerald@wireshark.org>
33 # Copyright 1998 Gerald Combs
35 # SPDX-License-Identifier: GPL-2.0-or-later
38 use strict;
39 use warnings;
41 use Getopt::Long;
43 my %EXPERT_SEVERITY = ('PI_COMMENT' => "PI_COMMENT",
44 'PI_CHAT' => "PI_CHAT",
45 'PI_NOTE' => "PI_NOTE",
46 'PI_WARN' => "PI_WARN",
47 'PI_ERROR' => "PI_ERROR");
49 my %EXPERT_GROUPS = ('PI_CHECKSUM' => "PI_CHECKSUM",
50 'PI_SEQUENCE' => "PI_SEQUENCE",
51 'PI_RESPONSE_CODE' => "PI_RESPONSE_CODE",
52 'PI_REQUEST_CODE' => "PI_REQUEST_CODE",
53 'PI_UNDECODED' => "PI_UNDECODED",
54 'PI_REASSEMBLE' => "PI_REASSEMBLE",
55 'PI_MALFORMED' => "PI_MALFORMED",
56 'PI_DEBUG' => "PI_DEBUG",
57 'PI_PROTOCOL' => "PI_PROTOCOL",
58 'PI_SECURITY' => "PI_SECURITY",
59 'PI_COMMENTS_GROUP' => "PI_COMMENTS_GROUP",
60 'PI_DECRYPTION' => "PI_DECRYPTION",
61 'PI_ASSUMPTION' => "PI_ASSUMPTION",
62 'PI_DEPRECATED' => "PI_DEPRECATED",
63 'PI_RECEIVE' => "PI_RECEIVE",
64 'PI_INTERFACE' => "PI_INTERFACE",
65 'PI_DISSECTOR_BUG' => "PI_DISSECTOR_BUG");
67 my @expert_list;
68 my $protabbrev = "";
70 # Perl trim function to remove whitespace from the start and end of the string
71 sub trim($)
73 my $string = shift;
74 $string =~ s/^\s+//;
75 $string =~ s/\s+$//;
76 return $string;
79 # ---------------------------------------------------------------------
81 # MAIN
83 my $helpFlag = '';
84 my $action = 'generate';
85 my $register = '';
87 my $result = GetOptions(
88 'action=s' => \$action,
89 'register' => \$register,
90 'help|?' => \$helpFlag
93 if (!$result || $helpFlag || !$ARGV[0]) {
94 usage();
97 sub usage {
98 print "\nUsage: $0 [--action=generate|fix-all|find-all] FILENAME [...]\n\n";
99 print " --action = generate (default)\n";
100 print " generate - create a delimited file (FILENAME.expert_add_info_input) with\n";
101 print " expert_add_info_format fields in FILENAME(s)\n";
102 print " fix-all - Use delimited file (FILENAME.expert_add_info_input) to convert\n";
103 print " expert_add_info_format to \"filterable\" expert API\n";
104 print " Also generates FILENAME.ei to be copy/pasted into\n";
105 print " the dissector where appropriate\n\n";
106 print " --register = generate ei_register_info and expert register function calls\n\n";
108 exit(1);
112 # XXX Outline general algorithm here
114 my $found_total = 0;
115 my $protabbrev_index;
116 my $line_number = 0;
118 while (my $fileName = $ARGV[0]) {
119 shift;
120 my $fileContents = '';
122 die "No such file: \"$fileName\"\n" if (! -e $fileName);
124 # delete leading './'
125 $fileName =~ s{ ^ \. / } {}xo;
127 #determine PROTABBREV for dissector based on file name format of (dirs)/packet-PROTABBREV.c
128 $protabbrev_index = rindex($fileName, "packet-");
129 if ($protabbrev_index == -1) {
130 print "$fileName doesn't fit format of packet-PROTABBREV.c\n";
131 next;
134 $protabbrev = substr($fileName, $protabbrev_index+length("packet-"));
135 $protabbrev_index = rindex($protabbrev, ".");
136 if ($protabbrev_index == -1) {
137 print "$fileName doesn't fit format of packet-PROTABBREV.c\n";
138 next;
140 $protabbrev = lc(substr($protabbrev, 0, $protabbrev_index));
142 # Read in the file (ouch, but it's easier that way)
143 open(FCI, "<", $fileName) || die("Couldn't open $fileName");
144 while (<FCI>) {
145 $fileContents .= $_;
147 close(FCI);
149 if ($action eq "generate") {
150 generate_eis(\$fileContents, $fileName);
153 if ($action eq "fix-all") {
154 # Read in the ei "input" file
155 $line_number = 0;
156 my $errors = 0;
157 open(FCI, "<", $fileName . ".expert_add_info_input") || die("Couldn't open $fileName.expert_add_info_input");
158 while(my $line=<FCI>){
159 my @expert_item = split(/;|\n/, $line);
161 $line_number++;
162 $errors += verify_line(@expert_item);
164 push(@expert_list, \@expert_item);
166 close(FCI);
168 if ($errors > 0) {
169 print "Aborting conversion.\n";
170 exit(-1);
173 fix_expert_add_info_format(\$fileContents, $fileName);
175 # Write out the ei data
176 output_ei_data($fileName);
178 # Write out the changed version to a file
179 open(FCO, ">", $fileName . ".expert_add_info_format");
180 print FCO "$fileContents";
181 close(FCO);
184 } # while
186 exit $found_total;
188 # ---------------------------------------------------------------------
189 # Sanity check the data in the .proto_tree_input file
190 sub verify_line {
191 my( @expert_item) = @_;
192 my $errors = 0;
194 #do some basic error checking of the file
195 if (($expert_item[0] eq "1") ||
196 ($expert_item[0] eq "2") ||
197 ($expert_item[0] eq "3") ||
198 ($expert_item[0] eq "4")) {
199 #expert info conversions
200 if (!($expert_item[2] =~ /^ei_/)) {
201 print "$line_number: Poorly formed ei_ variable ($expert_item[2])!\n";
202 $errors++;
204 } else {
205 print "$line_number: Bad conversion value!\n";
206 $errors++;
209 if ($expert_item[1] eq "1") {
210 if (!($expert_item[2] =~ /^ei_/)) {
211 print "$line_number: Poorly formed ei_ variable ($expert_item[2])!\n";
212 $errors++;
214 if (!exists($EXPERT_SEVERITY{$expert_item[4]})) {
215 print "$line_number: Expert severity value '$expert_item[5]' unknown!\n";
216 $errors++;
218 if (!exists($EXPERT_GROUPS{$expert_item[3]})) {
219 print "$line_number: Expert group value '$expert_item[4]' unknown!\n";
220 $errors++;
223 } elsif ($expert_item[1] ne "0") {
224 print "$line_number: Bad ei variable generation value!\n";
225 $errors++;
228 return $errors;
231 sub generate_eis {
232 my( $fileContentsRef, $fileName) = @_;
233 my @args;
234 my $num_items = 0;
235 my @temp;
236 my $str_temp;
237 my $pat;
239 $pat = qr /
241 (?:expert_add_info_format)\s* \(
242 (([^[\,;])*\,){4,}
243 [^;]*
244 \s* \) \s* ;
246 /xs;
248 while ($$fileContentsRef =~ / $pat /xgso) {
250 my @expert_item = (1, 1, "ei_name", "GROUP", "SEVERITY", "fieldfullname", "fieldabbrevname",
251 "pinfo", "item", "tvb", "offset", "length", "params");
252 my $arg_loop = 5;
253 my $str = "${1}\n";
254 $str =~ tr/\t\n\r/ /d;
255 $str =~ s/ \s+ / /xg;
256 #print "$fileName: $str\n";
258 @args = split(/,/, $str);
259 #printf "ARGS(%d): %s\n", scalar @args, join("# ", @args);
260 $args[0] =~ s/expert_add_info_format\s*\(\s*//;
262 $expert_item[7] = $args[0]; #pinfo
263 $expert_item[8] = trim($args[1]); #item
264 $expert_item[3] = trim($args[2]); #GROUP
265 $expert_item[4] = trim($args[3]); #SEVERITY
266 $expert_item[5] = trim($args[4]); #fieldfullname
267 $expert_item[5] =~ s/\"//;
269 #XXX - conditional?
270 $expert_item[5] =~ s/\"\s*\)\s*;$//;
271 $expert_item[5] =~ s/\"$//;
273 #params
274 $expert_item[12] = "";
275 while ($arg_loop < scalar @args) {
276 $expert_item[12] .= trim($args[$arg_loop]);
277 if ($arg_loop+1 < scalar @args) {
278 $expert_item[12] .= ", ";
280 $arg_loop += 1;
282 $expert_item[12] =~ s/\s*\)\s*;$//;
284 #ei variable name
285 $expert_item[2] = sprintf("ei_%s_%s", $protabbrev, lc($expert_item[5]));
286 $expert_item[2] =~ s/\s+|-|:/_/g;
288 #field abbreviated name
289 $expert_item[6] = sprintf("%s.%s", $protabbrev, lc($expert_item[5]));
290 $expert_item[6] =~ s/\s+|-|:/_/g;
292 push(@expert_list, \@expert_item);
294 $num_items += 1;
297 if ($num_items > 0) {
298 open(FCO, ">", $fileName . ".expert_add_info_input");
299 for my $item (@expert_list) {
300 print FCO join(";", @{$item}), "\n";
302 close(FCO);
306 # ---------------------------------------------------------------------
307 # Find all expert_add_info_format calls and replace them with the data
308 # found in expert_list
309 sub fix_expert_add_info_format {
310 my( $fileContentsRef, $fileName) = @_;
311 my $found = 0;
312 my $pat;
314 $pat = qr /
316 (?:expert_add_info_format)\s* \(
317 (([^[\,;])*\,){4,}
318 [^;]*
319 \s* \) \s* ;
321 /xs;
323 $$fileContentsRef =~ s/ $pat /patsub($found, $1)/xges;
326 # ---------------------------------------------------------------------
327 # Format expert info functions with expert_list data
328 sub patsub {
329 my $item_str;
331 #print $expert_list[$_[0]][2] . " = ";
332 #print $#{$expert_list[$_[0]]}+1;
333 #print "\n";
335 if ($expert_list[$_[0]][0] eq "1") {
336 $item_str = sprintf("expert_add_info(%s, %s, &%s);",
337 $expert_list[$_[0]][7], $expert_list[$_[0]][8], $expert_list[$_[0]][2]);
338 } elsif ($expert_list[$_[0]][0] eq "2") {
339 $item_str = sprintf("expert_add_info_format(%s, %s, &%s, \"%s\"",
340 $expert_list[$_[0]][7], $expert_list[$_[0]][8],
341 $expert_list[$_[0]][2], $expert_list[$_[0]][5]);
342 if (($#{$expert_list[$_[0]]}+1 > 12 ) && ($expert_list[$_[0]][12] ne "")) {
343 $item_str .= ", $expert_list[$_[0]][12]";
345 $item_str .= ");";
346 } elsif ($expert_list[$_[0]][0] eq "3") {
347 $item_str = sprintf("proto_tree_add_expert(%s, %s, &%s, %s, %s, %s);",
348 $expert_list[$_[0]][8], $expert_list[$_[0]][7],
349 $expert_list[$_[0]][2], $expert_list[$_[0]][9],
350 $expert_list[$_[0]][10], $expert_list[$_[0]][11]);
351 } elsif ($expert_list[$_[0]][0] eq "4") {
352 $item_str = sprintf("proto_tree_add_expert_format(%s, %s, &%s, %s, %s, %s, \"%s\"",
353 $expert_list[$_[0]][8], $expert_list[$_[0]][7], $expert_list[$_[0]][2],
354 $expert_list[$_[0]][9], $expert_list[$_[0]][10],
355 $expert_list[$_[0]][11], $expert_list[$_[0]][5]);
356 if (($#{$expert_list[$_[0]]}+1 > 12) && ($expert_list[$_[0]][12] ne "")) {
357 $item_str .= ", $expert_list[$_[0]][12]";
359 $item_str .= ");";
362 $_[0] += 1;
364 return $item_str;
367 # ---------------------------------------------------------------------
368 # Output the ei variable declarations and expert array. For now, write them to a file.
369 # XXX - Eventually find the right place to add it to the modified dissector file
370 sub output_ei_data {
371 my( $fileName) = @_;
372 my %eis = ();
373 my $index;
374 my $key;
376 #add ei to hash table to prevent against (accidental) duplicates
377 for ($index=0;$index<@expert_list;$index++) {
378 if ($expert_list[$index][1] eq "1") {
379 $eis{$expert_list[$index][2]} = $expert_list[$index][2];
383 open(FCO, ">", $fileName . ".ei");
385 print FCO "/* Generated from convert_expert_add_info_format.pl */\n";
387 foreach $key (keys %eis) {
388 print FCO "static expert_field $key = EI_INIT;\n";
390 print FCO "\n\n";
392 if ($register ne "") {
393 print FCO " static ei_register_info ei[] = {\n";
396 %eis = ();
397 for ($index=0;$index<@expert_list;$index++) {
398 if ($expert_list[$index][1] eq "1") {
399 if (exists($eis{$expert_list[$index][2]})) {
400 print "duplicate ei entry '$expert_list[$index][2]' found! Aborting conversion.\n";
401 exit(-1);
403 $eis{$expert_list[$index][2]} = $expert_list[$index][2];
405 print FCO " { &$expert_list[$index][2], { \"$expert_list[$index][6]\", $expert_list[$index][3], ";
406 print FCO "$expert_list[$index][4], \"$expert_list[$index][5]\", EXPFILL }},\r\n";
410 if ($register ne "") {
411 print FCO " };\n\n\n";
412 print FCO " expert_module_t* expert_$protabbrev;\n\n";
414 print FCO " expert_$protabbrev = expert_register_protocol(proto_$protabbrev);\n";
415 print FCO " expert_register_field_array(expert_$protabbrev, ei, array_length(ei));\n\n";
419 close(FCO);