r22520: Fix the TYPE command.
[Samba.git] / source / pidl / lib / Parse / Pidl / Wireshark / Conformance.pm
blobb53c56e7419f00a13afbacf794eb93fabfc77ab0
1 ###################################################
2 # parse an Wireshark conformance file
3 # Copyright jelmer@samba.org 2005
4 # released under the GNU GPL
6 =pod
8 =head1 NAME
10 Parse::Pidl::Wireshark::Conformance - Conformance file parser for Wireshark
12 =head1 DESCRIPTION
14 This module supports parsing Wireshark conformance files (*.cnf).
16 =head1 FILE FORMAT
18 Pidl needs additional data for Wireshark output. This data is read from
19 so-called conformance files. This section describes the format of these
20 files.
22 Conformance files are simple text files with a single command on each line.
23 Empty lines and lines starting with a '#' character are ignored.
24 Arguments to commands are seperated by spaces.
26 The following commands are currently supported:
28 =over 4
30 =item I<TYPE> name dissector ft_type base_type mask valsstring alignment
32 Register new data type with specified name, what dissector function to call
33 and what properties to give header fields for elements of this type.
35 =item I<NOEMIT> type
37 Suppress emitting a dissect_type function for the specified type
39 =item I<PARAM_VALUE> type param
41 Set parameter to specify to dissector function for given type.
43 =item I<HF_FIELD> hf title filter ft_type base_type valsstring mask description
45 Generate a custom header field with specified properties.
47 =item I<HF_RENAME> old_hf_name new_hf_name
49 Force the use of new_hf_name when the parser generator was going to
50 use old_hf_name.
52 This can be used in conjunction with HF_FIELD in order to make more than
53 one element use the same filter name.
55 =item I<STRIP_PREFIX> prefix
57 Remove the specified prefix from all function names (if present).
59 =item I<PROTOCOL> longname shortname filtername
61 Change the short-, long- and filter-name for the current interface in
62 Wireshark.
64 =item I<FIELD_DESCRIPTION> field desc
66 Change description for the specified header field. `field' is the hf name of the field.
68 =item I<IMPORT> dissector code...
70 Code to insert when generating the specified dissector. @HF@ and
71 @PARAM@ will be substituted.
73 =item I<TFS> hf_name "true string" "false string"
75 Override the text shown when a bitmap boolean value is enabled or disabled.
77 =item I<MANUAL> fn_name
79 Force pidl to not generate a particular function but allow the user
80 to write a function manually. This can be used to remove the function
81 for only one level for a particular element rather than all the functions and
82 ett/hf variables for a particular element as the NOEMIT command does.
84 =back
86 =head1 EXAMPLE
88 INFO_KEY OpenKey.Ke
90 =cut
92 package Parse::Pidl::Wireshark::Conformance;
94 require Exporter;
95 use vars qw($VERSION);
96 $VERSION = '0.01';
98 @ISA = qw(Exporter);
99 @EXPORT_OK = qw(ReadConformance ReadConformanceFH valid_ft_type valid_base_type);
101 use strict;
103 use Parse::Pidl qw(fatal warning error);
104 use Parse::Pidl::Util qw(has_property);
106 sub handle_type($$$$$$$$$$)
108 my ($pos,$data,$name,$dissectorname,$ft_type,$base_type,$mask,$valsstring,$alignment) = @_;
110 unless(defined($alignment)) {
111 error($pos, "incomplete TYPE command");
112 return;
115 unless ($dissectorname =~ /.*dissect_.*/) {
116 warning($pos, "dissector name does not contain `dissect'");
119 unless(valid_ft_type($ft_type)) {
120 warning($pos, "invalid FT_TYPE `$ft_type'");
123 unless (valid_base_type($base_type)) {
124 warning($pos, "invalid BASE_TYPE `$base_type'");
127 $dissectorname =~ s/^\"(.*)\"$/$1/g;
129 if (not ($dissectorname =~ /;$/)) {
130 warning($pos, "missing semicolon");
133 $data->{types}->{$name} = {
134 NAME => $name,
135 POS => $pos,
136 USED => 0,
137 DISSECTOR_NAME => $dissectorname,
138 FT_TYPE => $ft_type,
139 BASE_TYPE => $base_type,
140 MASK => $mask,
141 VALSSTRING => $valsstring,
142 ALIGNMENT => $alignment
146 sub handle_tfs($$$$$)
148 my ($pos,$data,$hf,$trues,$falses) = @_;
150 unless(defined($falses)) {
151 error($pos, "incomplete TFS command");
152 return;
155 $data->{tfs}->{$hf} = {
156 TRUE_STRING => $trues,
157 FALSE_STRING => $falses
161 sub handle_hf_rename($$$$)
163 my ($pos,$data,$old,$new) = @_;
165 unless(defined($new)) {
166 warning($pos, "incomplete HF_RENAME command");
167 return;
170 $data->{hf_renames}->{$old} = {
171 OLDNAME => $old,
172 NEWNAME => $new,
173 POS => $pos,
174 USED => 0
178 sub handle_param_value($$$$)
180 my ($pos,$data,$dissector_name,$value) = @_;
182 unless(defined($value)) {
183 error($pos, "incomplete PARAM_VALUE command");
184 return;
187 $data->{dissectorparams}->{$dissector_name} = {
188 DISSECTOR => $dissector_name,
189 PARAM => $value,
190 POS => $pos,
191 USED => 0
195 sub valid_base_type($)
197 my $t = shift;
198 return 0 unless($t =~ /^BASE_.*/);
199 return 1;
202 sub valid_ft_type($)
204 my $t = shift;
205 return 0 unless($t =~ /^FT_.*/);
206 return 1;
209 sub handle_hf_field($$$$$$$$$$)
211 my ($pos,$data,$index,$name,$filter,$ft_type,$base_type,$valsstring,$mask,$blurb) = @_;
213 unless(defined($blurb)) {
214 error($pos, "incomplete HF_FIELD command");
215 return;
218 unless(valid_ft_type($ft_type)) {
219 warning($pos, "invalid FT_TYPE `$ft_type'");
222 unless(valid_base_type($base_type)) {
223 warning($pos, "invalid BASE_TYPE `$base_type'");
226 $data->{header_fields}->{$index} = {
227 INDEX => $index,
228 POS => $pos,
229 USED => 0,
230 NAME => $name,
231 FILTER => $filter,
232 FT_TYPE => $ft_type,
233 BASE_TYPE => $base_type,
234 VALSSTRING => $valsstring,
235 MASK => $mask,
236 BLURB => $blurb
240 sub handle_strip_prefix($$$)
242 my ($pos,$data,$x) = @_;
244 push (@{$data->{strip_prefixes}}, $x);
247 sub handle_noemit($$$)
249 my ($pos,$data,$type) = @_;
251 if (defined($type)) {
252 $data->{noemit}->{$type} = 1;
253 } else {
254 $data->{noemit_dissector} = 1;
258 sub handle_manual($$$)
260 my ($pos,$data,$fn) = @_;
262 unless(defined($fn)) {
263 warning($pos, "incomplete MANUAL command");
264 return;
267 $data->{manual}->{$fn} = 1;
270 sub handle_protocol($$$$$$)
272 my ($pos, $data, $name, $longname, $shortname, $filtername) = @_;
274 $data->{protocols}->{$name} = {
275 LONGNAME => $longname,
276 SHORTNAME => $shortname,
277 FILTERNAME => $filtername
281 sub handle_fielddescription($$$$)
283 my ($pos,$data,$field,$desc) = @_;
285 unless(defined($desc)) {
286 warning($pos, "incomplete FIELD_DESCRIPTION command");
287 return;
290 $data->{fielddescription}->{$field} = {
291 DESCRIPTION => $desc,
292 POS => $pos,
293 USED => 0
297 sub handle_import
299 my $pos = shift @_;
300 my $data = shift @_;
301 my $dissectorname = shift @_;
303 unless(defined($dissectorname)) {
304 error($pos, "no dissectorname specified");
305 return;
308 $data->{imports}->{$dissectorname} = {
309 NAME => $dissectorname,
310 DATA => join(' ', @_),
311 USED => 0,
312 POS => $pos
316 my %field_handlers = (
317 TYPE => \&handle_type,
318 NOEMIT => \&handle_noemit,
319 MANUAL => \&handle_manual,
320 PARAM_VALUE => \&handle_param_value,
321 HF_FIELD => \&handle_hf_field,
322 HF_RENAME => \&handle_hf_rename,
323 TFS => \&handle_tfs,
324 STRIP_PREFIX => \&handle_strip_prefix,
325 PROTOCOL => \&handle_protocol,
326 FIELD_DESCRIPTION => \&handle_fielddescription,
327 IMPORT => \&handle_import
330 sub ReadConformance($$)
332 my ($f,$data) = @_;
333 my $ret;
335 open(IN,"<$f") or return undef;
337 $ret = ReadConformanceFH(*IN, $data, $f);
339 close(IN);
341 return $ret;
344 sub ReadConformanceFH($$$)
346 my ($fh,$data,$f) = @_;
348 my $incodeblock = 0;
350 my $ln = 0;
352 foreach (<$fh>) {
353 $ln++;
354 next if (/^#.*$/);
355 next if (/^$/);
357 s/[\r\n]//g;
359 if ($_ eq "CODE START") {
360 $incodeblock = 1;
361 next;
362 } elsif ($incodeblock and $_ eq "CODE END") {
363 $incodeblock = 0;
364 next;
365 } elsif ($incodeblock) {
366 if (exists $data->{override}) {
367 $data->{override}.="$_\n";
368 } else {
369 $data->{override} = "$_\n";
371 next;
374 my @fields = /([^ "]+|"[^"]+")/g;
376 my $cmd = $fields[0];
378 shift @fields;
380 my $pos = { FILE => $f, LINE => $ln };
382 next unless(defined($cmd));
384 if (not defined($field_handlers{$cmd})) {
385 warning($pos, "Unknown command `$cmd'");
386 next;
389 $field_handlers{$cmd}($pos, $data, @fields);
392 if ($incodeblock) {
393 warning({ FILE => $f, LINE => $ln },
394 "Expecting CODE END");
395 return undef;
398 return 1;