nexmon – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 #!/usr/bin/perl
2 #
3 # Script to convert xcbproto and mesa protocol files for
4 # X11 dissector. Creates header files containing code to
5 # dissect X11 extensions.
6 #
7 # Instructions for using this script are in epan/dissectors/README.X11
8 #
9 # Copyright 2008, 2009, 2013, 2014 Open Text Corporation <pharris[AT]opentext.com>
10 #
11 # Wireshark - Network traffic analyzer
12 # By Gerald Combs <gerald@wireshark.org>
13 # Copyright 1998 Gerald Combs
14 #
15 # This program is free software; you can redistribute it and/or
16 # modify it under the terms of the GNU General Public License
17 # as published by the Free Software Foundation; either version 2
18 # of the License, or (at your option) any later version.
19 #
20 # This program is distributed in the hope that it will be useful,
21 # but WITHOUT ANY WARRANTY; without even the implied warranty of
22 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 # GNU General Public License for more details.
24 #
25 # You should have received a copy of the GNU General Public License
26 # along with this program; if not, write to the Free Software
27 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
28 #
29  
30 #TODO
31 # - support constructs that are legal in XCB, but don't appear to be used
32  
33 use 5.010;
34  
35 use warnings;
36 use strict;
37  
38 # given/when is going to be removed (and/or dramatically altered)
39 # in 5.20. Patches welcome.
40 # Patches even more welcome if they rewrite this whole thing in a
41 # language with a proper compatibility document, such as
42 # http://golang.org/doc/go1compat
43 no if $] >= 5.018, warnings => "experimental::smartmatch";
44  
45 use IO::File;
46 use XML::Twig;
47  
48 use File::Spec;
49  
50 my $srcdir = shift;
51 die "'$srcdir' is not a directory" unless -d $srcdir;
52  
53 my @reslist = grep {!/xproto\.xml$/} glob File::Spec->catfile($srcdir, 'xcbproto', 'src', '*.xml');
54 my @register;
55  
56 my $script_name = File::Spec->abs2rel ($0, $srcdir);
57  
58 my %basictype = (
59 char => { size => 1, encoding => 'ENC_ASCII|ENC_NA', type => 'FT_STRING', base => 'BASE_NONE', get => 'VALUE8', list => 'listOfByte', },
60 void => { size => 1, encoding => 'ENC_NA', type => 'FT_BYTES', base => 'BASE_NONE', get => 'VALUE8', list => 'listOfByte', },
61 BYTE => { size => 1, encoding => 'ENC_NA', type => 'FT_BYTES', base => 'BASE_NONE', get => 'VALUE8', list => 'listOfByte', },
62 CARD8 => { size => 1, encoding => 'byte_order', type => 'FT_UINT8', base => 'BASE_HEX_DEC', get => 'VALUE8', list => 'listOfByte', },
63 CARD16 => { size => 2, encoding => 'byte_order', type => 'FT_UINT16', base => 'BASE_HEX_DEC', get => 'VALUE16', list => 'listOfCard16', },
64 CARD32 => { size => 4, encoding => 'byte_order', type => 'FT_UINT32', base => 'BASE_HEX_DEC', get => 'VALUE32', list => 'listOfCard32', },
65 CARD64 => { size => 8, encoding => 'byte_order', type => 'FT_UINT64', base => 'BASE_HEX_DEC', get => 'VALUE64', list => 'listOfCard64', },
66 INT8 => { size => 1, encoding => 'byte_order', type => 'FT_INT8', base => 'BASE_DEC', get => 'VALUE8', list => 'listOfByte', },
67 INT16 => { size => 2, encoding => 'byte_order', type => 'FT_INT16', base => 'BASE_DEC', get => 'VALUE16', list => 'listOfInt16', },
68 INT32 => { size => 4, encoding => 'byte_order', type => 'FT_INT32', base => 'BASE_DEC', get => 'VALUE32', list => 'listOfInt32', },
69 INT64 => { size => 8, encoding => 'byte_order', type => 'FT_INT64', base => 'BASE_DEC', get => 'VALUE64', list => 'listOfInt64', },
70 float => { size => 4, encoding => 'byte_order', type => 'FT_FLOAT', base => 'BASE_NONE', get => 'FLOAT', list => 'listOfFloat', },
71 double => { size => 8, encoding => 'byte_order', type => 'FT_DOUBLE', base => 'BASE_NONE', get => 'DOUBLE', list => 'listOfDouble', },
72 BOOL => { size => 1, encoding => 'byte_order', type => 'FT_BOOLEAN',base => 'BASE_NONE', get => 'VALUE8', list => 'listOfByte', },
73 );
74  
75 my %simpletype; # Reset at the beginning of each extension
76 my %gltype; # No need to reset, since it's only used once
77  
78 my %struct = # Not reset; contains structures already defined.
79 # Also contains this black-list of structures never used by any
80 # extension (to avoid generating useless code).
81 (
82 # structures defined by xproto, but not used by any extension
83 'xproto:CHAR2B' => 1,
84 'xproto:ARC' => 1,
85 'xproto:FORMAT' => 1,
86 'xproto:VISUALTYPE' => 1,
87 'xproto:DEPTH' => 1,
88 'xproto:SCREEN' => 1,
89 'xproto:SetupRequest' => 1,
90 'xproto:SetupFailed' => 1,
91 'xproto:SetupAuthenticate' => 1,
92 'xproto:Setup' => 1,
93 'xproto:TIMECOORD' => 1,
94 'xproto:FONTPROP' => 1,
95 'xproto:CHARINFO' => 1,
96 'xproto:SEGMENT' => 1,
97 'xproto:COLORITEM' => 1,
98 'xproto:RGB' => 1,
99 'xproto:HOST' => 1,
100 'xproto:POINT' => 1,
101  
102 # structures defined by xinput, but never used (except by each other)(bug in xcb?)
103 'xinput:KeyInfo' => 1,
104 'xinput:ButtonInfo' => 1,
105 'xinput:ValuatorInfo' => 1,
106 'xinput:KbdFeedbackState' => 1,
107 'xinput:PtrFeedbackState' => 1,
108 'xinput:IntegerFeedbackState' => 1,
109 'xinput:StringFeedbackState' => 1,
110 'xinput:BellFeedbackState' => 1,
111 'xinput:LedFeedbackState' => 1,
112 'xinput:KbdFeedbackCtl' => 1,
113 'xinput:PtrFeedbackCtl' => 1,
114 'xinput:IntegerFeedbackCtl' => 1,
115 'xinput:StringFeedbackCtl' => 1,
116 'xinput:BellFeedbackCtl' => 1,
117 'xinput:LedFeedbackCtl' => 1,
118 'xinput:KeyState' => 1,
119 'xinput:ButtonState' => 1,
120 'xinput:ValuatorState' => 1,
121 'xinput:DeviceResolutionState' => 1,
122 'xinput:DeviceAbsCalibState' => 1,
123 'xinput:DeviceAbsAreaState' => 1,
124 'xinput:DeviceCoreState' => 1,
125 'xinput:DeviceEnableState' => 1,
126 'xinput:DeviceResolutionCtl' => 1,
127 'xinput:DeviceAbsCalibCtl' => 1,
128 'xinput:DeviceAbsAreaCtrl' => 1,
129 'xinput:DeviceCoreCtrl' => 1,
130 'xinput:DeviceEnableCtrl' => 1,
131 'xinput:DeviceName' => 1,
132 'xinput:AddMaster' => 1,
133 'xinput:RemoveMaster' => 1,
134 'xinput:AttachSlave' => 1,
135 'xinput:DetachSlave' => 1,
136 'xinput:ButtonClass' => 1,
137 'xinput:KeyClass' => 1,
138 'xinput:ScrollClass' => 1,
139 'xinput:TouchClass' => 1,
140 'xinput:ValuatorClass' => 1,
141  
142 # structures defined by xv, but never used (bug in xcb?)
143 'xv:Image' => 1,
144  
145 # structures defined by xkb, but never used (except by each other)(bug in xcb?)
146 'xkb:Key' => 1,
147 'xkb:Outline' => 1,
148 'xkb:Overlay' => 1,
149 'xkb:OverlayKey' => 1,
150 'xkb:OverlayRow' => 1,
151 'xkb:Row' => 1,
152 'xkb:Shape' => 1,
153 );
154 my %enum; # Not reset; contains enums already defined.
155 my %enum_name;
156 my %type_name;
157 my $header;
158 my $extname;
159 my @incname;
160 my %request;
161 my %genericevent;
162 my %event;
163 my %reply;
164  
165 # Output files
166 my $impl;
167 my $reg;
168 my $decl;
169 my $error;
170  
171 # glRender sub-op output files
172 my $enum;
173  
174 # Mesa API definitions keep moving
175 my @mesas = ($srcdir . '/mesa/src/mapi/glapi/gen', # 2010-04-26
176 $srcdir . '/mesa/src/mesa/glapi/gen', # 2010-02-22
177 $srcdir . '/mesa/src/mesa/glapi'); # 2004-05-18
178 my $mesadir = (grep { -d } @mesas)[0];
179  
180 sub mesa_category_start {
181 my ($t, $elt) = @_;
182 my $name = $elt->att('name');
183 my $comment;
184 if ($name =~ /^\d\.\d$/) {
185 $comment = "version $name";
186 } else {
187 $comment = "extension $name";
188 }
189  
190 print $enum "/* OpenGL $comment */\n";
191 print(" - $comment\n");
192 }
193  
194 sub mesa_category {
195 my ($t, $elt) = @_;
196 $t->purge;
197 }
198  
199 sub mesa_enum {
200 my ($t, $elt) = @_;
201 my $name = $elt->att('name');
202 my $value = $elt->att('value');
203  
204 print $enum " { $value, \"$name\" },\n" if (length($value) > 3 && length($value) < 10);
205 $t->purge;
206 }
207  
208 sub mesa_type {
209 my ($t, $elt) = @_;
210  
211 my $name = $elt->att('name');
212 my $size = $elt->att('size');
213 my $float = $elt->att('float');
214 my $unsigned = $elt->att('unsigned');
215 my $base;
216  
217 $t->purge;
218  
219 if($name eq 'enum') {
220 # enum does not have a direct X equivalent
221 $gltype{'GLenum'} = { size => 4, encoding => 'byte_order', type => 'FT_UINT32', base => 'BASE_HEX',
222 get => 'VALUE32', list => 'listOfCard32',
223 val => 'VALS(mesa_enum)', };
224 return;
225 }
226  
227 $name = 'GL'.$name;
228 if (defined($float) && $float eq 'true') {
229 $base = 'float';
230 $base = 'double' if ($size == 8);
231 } else {
232 $base = 'INT';
233 if (defined($unsigned) && $unsigned eq 'true') {
234 $base = 'CARD';
235 }
236 $base .= ($size * 8);
237  
238 $base = 'BOOL' if ($name eq 'bool');
239 $base = 'BYTE' if ($name eq 'void');
240 }
241  
242 $gltype{$name} = $basictype{$base};
243 }
244  
245 sub registered_name($$)
246 {
247 my $name = shift;
248 my $field = shift;
249  
250 return "hf_x11_$header"."_$name"."_$field";
251 }
252  
253 sub mesa_function {
254 my ($t, $elt) = @_;
255 # rop == glRender sub-op
256 # sop == GLX minor opcode
257 my $glx = $elt->first_child('glx');
258 unless(defined $glx) { $t->purge; return; }
259  
260 my $rop = $glx->att('rop');
261 unless (defined $rop) { $t->purge; return; }
262  
263 # Ideally, we want the main name, not the alias name.
264 # Practically, we'd have to scan the file twice to find
265 # the functions that we want to skip.
266 my $alias = $elt->att('alias');
267 if (defined $alias) { $t->purge; return; }
268  
269 my $name = $elt->att('name');
270 $request{$rop} = $name;
271  
272 my $image;
273  
274 my $length = 0;
275 my @elements = $elt->children('param');
276  
277 # Wireshark defines _U_ to mean "Unused" (compiler specific define)
278 if (!@elements) {
279 print $impl <<eot
280 static void mesa_$name(tvbuff_t *tvb _U_, int *offsetp _U_, proto_tree *t _U_, guint byte_order _U_, int length _U_)
281 {
282 eot
283 ;
284 } else {
285 print $impl <<eot
286 static void mesa_$name(tvbuff_t *tvb, int *offsetp, proto_tree *t, guint byte_order, int length _U_)
287 {
288 eot
289 ;
290 }
291  
292 my %type_param;
293 foreach my $e (@elements) {
294 # Detect count && variable_param
295 my $count = $e->att('count');
296 my $variable_param = $e->att('variable_param');
297 if (defined $count and defined $variable_param) {
298 $type_param{$variable_param} = 1;
299 }
300 }
301 foreach my $e (@elements) {
302 # Register field with wireshark
303  
304 my $type = $e->att('type');
305 $type =~ s/^const //;
306 my $list;
307 $list = 1 if ($type =~ /\*$/);
308 $type =~ s/ \*$//;
309  
310 my $fieldname = $e->att('name');
311 my $regname = registered_name($name, $fieldname);
312  
313 my $info = $gltype{$type};
314 my $ft = $info->{'type'};
315 my $base = $info->{'base'};
316 my $val = $info->{'val'} // 'NULL';
317 my $count = $e->att('count');
318 my $variable_param = $e->att('variable_param');
319  
320 if ($list and $count and $variable_param) {
321 print $decl "static int ${regname} = -1;\n";
322 print $reg "{ &$regname, { \"$fieldname\", \"x11.glx.render.$name.$fieldname\", FT_NONE, BASE_NONE, NULL, 0, NULL, HFILL }},\n";
323 print $decl "static int ${regname}_signed = -1;\n";
324 print $reg "{ &${regname}_signed, { \"$fieldname\", \"x11.glx.render.$name.$fieldname\", FT_INT8, BASE_DEC, NULL, 0, NULL, HFILL }},\n";
325 print $decl "static int ${regname}_unsigned = -1;\n";
326 print $reg "{ &${regname}_unsigned, { \"$fieldname\", \"x11.glx.render.$name.$fieldname\", FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }},\n";
327 print $decl "static int ${regname}_item_card16 = -1;\n";
328 print $reg "{ &${regname}_item_card16, { \"$fieldname\", \"x11.glx.render.$name.$fieldname\", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }},\n";
329 print $decl "static int ${regname}_item_int16 = -1;\n";
330 print $reg "{ &${regname}_item_int16, { \"$fieldname\", \"x11.glx.render.$name.$fieldname\", FT_INT16, BASE_DEC, NULL, 0, NULL, HFILL }},\n";
331 print $decl "static int ${regname}_item_card32 = -1;\n";
332 print $reg "{ &${regname}_item_card32, { \"$fieldname\", \"x11.glx.render.$name.$fieldname\", FT_UINT32, BASE_DEC, NULL, 0, NULL, HFILL }},\n";
333 print $decl "static int ${regname}_item_int32 = -1;\n";
334 print $reg "{ &${regname}_item_int32, { \"$fieldname\", \"x11.glx.render.$name.$fieldname\", FT_INT32, BASE_DEC, NULL, 0, NULL, HFILL }},\n";
335 print $decl "static int ${regname}_item_float = -1;\n";
336 print $reg "{ &${regname}_item_float, { \"$fieldname\", \"x11.glx.render.$name.$fieldname\", FT_FLOAT, BASE_NONE, NULL, 0, NULL, HFILL }},\n";
337 } else {
338 print $decl "static int $regname = -1;\n";
339 if ($list and $info->{'size'} > 1) {
340 print $reg "{ &$regname, { \"$fieldname\", \"x11.glx.render.$name.$fieldname\", FT_NONE, BASE_NONE, NULL, 0, NULL, HFILL }},\n";
341 $regname .= '_item';
342 print $decl "static int $regname = -1;\n";
343 }
344 print $reg "{ &$regname, { \"$fieldname\", \"x11.glx.render.$name.$fieldname\", $ft, $base, $val, 0, NULL, HFILL }},\n";
345  
346 if ($e->att('counter') or $type_param{$fieldname}) {
347 print $impl " int $fieldname;\n";
348 }
349 }
350  
351 if ($list) {
352 if ($e->att('img_format')) {
353 $image = 1;
354 foreach my $wholename (('swap bytes', 'lsb first')) {
355 # Boolean values
356 my $varname = $wholename;
357 $varname =~ s/\s//g;
358 my $regname = registered_name($name, $varname);
359 print $decl "static int $regname = -1;\n";
360 print $reg "{ &$regname, { \"$wholename\", \"x11.glx.render.$name.$varname\", FT_BOOLEAN, BASE_NONE, NULL, 0, NULL, HFILL }},\n";
361 }
362 foreach my $wholename (('row length', 'skip rows', 'skip pixels', 'alignment')) {
363 # Integer values
364 my $varname = $wholename;
365 $varname =~ s/\s//g;
366 my $regname = registered_name($name, $varname);
367 print $decl "static int $regname = -1;\n";
368 print $reg "{ &$regname, { \"$wholename\", \"x11.glx.render.$name.$varname\", FT_UINT32, BASE_HEX_DEC, NULL, 0, NULL, HFILL }},\n";
369 }
370 }
371 }
372 }
373  
374 # The image requests have a few implicit elements first:
375 if ($image) {
376 foreach my $wholename (('swap bytes', 'lsb first')) {
377 # Boolean values
378 my $varname = $wholename;
379 $varname =~ s/\s//g;
380 my $regname = registered_name($name, $varname);
381 print $impl " proto_tree_add_item(t, $regname, tvb, *offsetp, 1, byte_order);\n";
382 print $impl " *offsetp += 1;\n";
383 $length += 1;
384 }
385 print $impl " UNUSED(2);\n";
386 $length += 2;
387 foreach my $wholename (('row length', 'skip rows', 'skip pixels', 'alignment')) {
388 # Integer values
389 my $varname = $wholename;
390 $varname =~ s/\s//g;
391 my $regname = registered_name($name, $varname);
392 print $impl " proto_tree_add_item(t, $regname, tvb, *offsetp, 4, byte_order);\n";
393 print $impl " *offsetp += 4;\n";
394 $length += 4;
395 }
396 }
397  
398 foreach my $e (@elements) {
399 my $type = $e->att('type');
400 $type =~ s/^const //;
401 my $list;
402 $list = 1 if ($type =~ /\*$/);
403 $type =~ s/ \*$//;
404  
405 my $fieldname = $e->att('name');
406 my $regname = registered_name($name, $fieldname);
407  
408 my $info = $gltype{$type};
409 my $ft = $info->{'type'};
410 my $base = $info->{'base'};
411  
412 if (!$list) {
413 my $size = $info->{'size'};
414 my $encoding = $info->{'encoding'};
415 my $get = $info->{'get'};
416  
417 if ($e->att('counter') or $type_param{$fieldname}) {
418 print $impl " $fieldname = $get(tvb, *offsetp);\n";
419 }
420 print $impl " proto_tree_add_item(t, $regname, tvb, *offsetp, $size, $encoding);\n";
421 print $impl " *offsetp += $size;\n";
422 $length += $size;
423 } else { # list
424 my $list = $info->{'list'};
425 my $count = $e->att('count');
426 my $variable_param = $e->att('variable_param');
427  
428 if (defined($count) && !defined($variable_param)) {
429 $regname .= ", $regname".'_item' if ($info->{'size'} > 1);
430 print $impl " $list(tvb, offsetp, t, $regname, $count, byte_order);\n";
431 } else {
432 if (defined($count)) {
433 # Currently, only CallLists has both a count and a variable_param
434 # The XML contains a size description of all the possibilities
435 # for CallLists, but not a type description. Implement by hand,
436 # with the caveat that more types may need to be added in the
437 # future.
438 say $impl " switch($variable_param) {";
439 say $impl " case 0x1400: /* BYTE */";
440 say $impl " listOfByte(tvb, offsetp, t, ${regname}_signed, $count, byte_order);";
441 say $impl " UNUSED(length - $length - $count);";
442 say $impl " break;";
443 say $impl " case 0x1401: /* UNSIGNED_BYTE */";
444 say $impl " listOfByte(tvb, offsetp, t, ${regname}_unsigned, $count, byte_order);";
445 say $impl " UNUSED(length - $length - $count);";
446 say $impl " break;";
447 say $impl " case 0x1402: /* SHORT */";
448 say $impl " listOfInt16(tvb, offsetp, t, $regname, ${regname}_item_int16, $count, byte_order);";
449 say $impl " UNUSED(length - $length - 2 * $count);";
450 say $impl " break;";
451 say $impl " case 0x1403: /* UNSIGNED_SHORT */";
452 say $impl " listOfCard16(tvb, offsetp, t, $regname, ${regname}_item_card16, $count, byte_order);";
453 say $impl " UNUSED(length - $length - 2 * $count);";
454 say $impl " break;";
455 say $impl " case 0x1404: /* INT */";
456 say $impl " listOfInt32(tvb, offsetp, t, $regname, ${regname}_item_int32, $count, byte_order);";
457 say $impl " break;";
458 say $impl " case 0x1405: /* UNSIGNED_INT */";
459 say $impl " listOfCard32(tvb, offsetp, t, $regname, ${regname}_item_card32, $count, byte_order);";
460 say $impl " break;";
461 say $impl " case 0x1406: /* FLOAT */";
462 say $impl " listOfFloat(tvb, offsetp, t, $regname, ${regname}_item_float, $count, byte_order);";
463 say $impl " break;";
464 say $impl " case 0x1407: /* 2_BYTES */";
465 say $impl " listOfCard16(tvb, offsetp, t, $regname, ${regname}_item_card16, $count, ENC_BIG_ENDIAN);";
466 say $impl " UNUSED(length - $length - 2 * $count);";
467 say $impl " break;";
468 say $impl " case 0x1408: /* 3_BYTES */";
469 say $impl " UNDECODED(3 * $count);";
470 say $impl " UNUSED(length - $length - 3 * $count);";
471 say $impl " break;";
472 say $impl " case 0x1409: /* 4_BYTES */";
473 say $impl " listOfCard32(tvb, offsetp, t, $regname, ${regname}_item_card32, $count, ENC_BIG_ENDIAN);";
474 say $impl " break;";
475 say $impl " case 0x140B: /* HALF_FLOAT */";
476 say $impl " UNDECODED(2 * $count);";
477 say $impl " UNUSED(length - $length - 2 * $count);";
478 say $impl " break;";
479 say $impl " default: /* Unknown */";
480 say $impl " UNDECODED(length - $length);";
481 say $impl " break;";
482 say $impl " }";
483 } else {
484 $regname .= ", $regname".'_item' if ($info->{'size'} > 1);
485 print $impl " $list(tvb, offsetp, t, $regname, (length - $length) / $gltype{$type}{'size'}, byte_order);\n";
486 }
487 }
488 }
489 }
490  
491 print $impl "}\n\n";
492 $t->purge;
493 }
494  
495 sub get_op($;$);
496 sub get_unop($;$);
497  
498 sub get_ref($$)
499 {
500 my $elt = shift;
501 my $refref = shift;
502 my $rv;
503  
504 given($elt->name()) {
505 when ('fieldref') {
506 $rv = $elt->text();
507 $refref->{$rv} = 1;
508 $rv = 'f_'.$rv;
509 }
510 when ('value') { $rv = $elt->text(); }
511 when ('op') { $rv = get_op($elt, $refref); }
512 when (['unop','popcount']) { $rv = get_unop($elt, $refref); }
513 default { die "Invalid op fragment: $_" }
514 }
515 return $rv;
516 }
517  
518 sub get_op($;$) {
519 my $op = shift;
520 my $refref = shift // {};
521  
522 my @elements = $op->children(qr/fieldref|value|op|unop|popcount/);
523 (@elements == 2) or die ("Wrong number of children for 'op'\n");
524 my $left;
525 my $right;
526  
527 $left = get_ref($elements[0], $refref);
528 $right = get_ref($elements[1], $refref);
529  
530 return "($left " . $op->att('op') . " $right)";
531 }
532  
533 sub get_unop($;$) {
534 my $op = shift;
535 my $refref = shift // {};
536  
537 my @elements = $op->children(qr/fieldref|value|op|unop|popcount/);
538 (@elements == 1) or die ("Wrong number of children for 'unop'\n");
539 my $left;
540  
541 $left = get_ref($elements[0], $refref);
542  
543 given ($op->name()) {
544 when ('unop') {
545 return '(' . $op->att('op') . "$left)";
546 }
547 when ('popcount') {
548 return "popcount($left)";
549 }
550 default { die "Invalid unop element $op->name()\n"; }
551 }
552 }
553  
554 sub qualname {
555 my $name = shift;
556 $name = $incname[0].':'.$name unless $name =~ /:/;
557 return $name
558 }
559  
560 sub get_simple_info {
561 my $name = shift;
562 my $info = $basictype{$name};
563 return $info if (defined $info);
564 $info = $simpletype{$name};
565 return $info if (defined $info);
566 if (defined($type_name{$name})) {
567 return $simpletype{$type_name{$name}};
568 }
569 return undef
570 }
571  
572 sub get_struct_info {
573 my $name = shift;
574 my $info = $struct{$name};
575 return $info if (defined $info);
576 if (defined($type_name{$name})) {
577 return $struct{$type_name{$name}};
578 }
579 return undef
580 }
581  
582 sub getinfo {
583 my $name = shift;
584 my $info = get_simple_info($name) // get_struct_info($name);
585 # If the script fails here search for $name in this script and remove it from the black list
586 die "$name is defined to be unused in process-x11-xcb.pl but is actually used!" if (defined($info) && $info == "1");
587 return $info;
588 }
589  
590 sub dump_enum_values($)
591 {
592 my $e = shift;
593  
594 defined($enum{$e}) or die("Enum $e not found");
595  
596 my $enumname = "x11_enum_$e";
597 return $enumname if (defined $enum{$e}{done});
598  
599 say $enum 'static const value_string '.$enumname.'[] = {';
600  
601 my $value = $enum{$e}{value};
602 for my $val (sort { $a <=> $b } keys %$value) {
603 say $enum sprintf(" { %3d, \"%s\" },", $val, $$value{$val});
604 }
605 say $enum sprintf(" { %3d, NULL },", 0);
606 say $enum '};';
607 say $enum '';
608  
609 $enum{$e}{done} = 1;
610 return $enumname;
611 }
612  
613 # Find all references, so we can declare only the minimum necessary
614 sub reference_elements($$);
615  
616 sub reference_elements($$)
617 {
618 my $e = shift;
619 my $refref = shift;
620  
621 given ($e->name()) {
622 when ('switch') {
623 my $lentype = $e->first_child();
624 if (defined $lentype) {
625 given ($lentype->name()) {
626 when ('fieldref') { $refref->{field}{$lentype->text()} = 1; }
627 when ('op') { get_op($lentype, $refref->{field}); }
628 }
629 }
630  
631 my @elements = $e->children(qr/(bit)?case/);
632 for my $case (@elements) {
633 my @sub_elements = $case->children(qr/list|switch/);
634  
635 foreach my $sub_e (@sub_elements) {
636 reference_elements($sub_e, $refref);
637 }
638 }
639 }
640 when ('list') {
641 my $type = $e->att('type');
642 my $info = getinfo($type);
643 if (defined $info->{paramref}) {
644 for my $pref (keys %{$info->{paramref}}) {
645 $refref->{field}{$pref} = 1;
646 }
647 }
648  
649 my $lentype = $e->first_child();
650 if (defined $lentype) {
651 given ($lentype->name()) {
652 when ('fieldref') { $refref->{field}{$lentype->text()} = 1; }
653 when ('op') { get_op($lentype, $refref->{field}); }
654 when (['unop','popcount']) { get_unop($lentype, $refref->{field}); }
655 when ('sumof') { $refref->{sumof}{$lentype->att('ref')} = 1; }
656 }
657 } else {
658 $refref->{field}{'length'} = 1;
659 $refref->{'length'} = 1;
660 }
661 }
662 }
663 }
664  
665 sub register_element($$$$;$)
666 {
667 my $e = shift;
668 my $varpat = shift;
669 my $humanpat = shift;
670 my $refref = shift;
671 my $indent = shift // ' ' x 4;
672  
673 given ($e->name()) {
674 when ('pad') { return; } # Pad has no variables
675 when ('switch') { return; } # Switch defines varaibles in a tighter scope to avoid collisions
676 }
677  
678 # Register field with wireshark
679  
680 my $fieldname = $e->att('name');
681 my $type = $e->att('type') or die ("Field $fieldname does not have a valid type\n");
682  
683 my $regname = 'hf_x11_'.sprintf ($varpat, $fieldname);
684 my $humanname = 'x11.'.sprintf ($humanpat, $fieldname);
685  
686 my $info = getinfo($type);
687 my $ft = $info->{'type'} // 'FT_NONE';
688 my $base = $info->{'base'} // 'BASE_NONE';
689 my $vals = 'NULL';
690  
691 my $enum = $e->att('enum') // $e->att('altenum');
692 if (defined $enum) {
693 my $enumname = dump_enum_values($enum_name{$enum});
694 $vals = "VALS($enumname)";
695  
696 # Wireshark does not allow FT_BYTES, FT_BOOLEAN, or BASE_NONE to have an enum
697 $ft =~ s/FT_BYTES/FT_UINT8/;
698 $ft =~ s/FT_BOOLEAN/FT_UINT8/;
699 $base =~ s/BASE_NONE/BASE_DEC/;
700 }
701  
702 $enum = $e->att('mask');
703 if (defined $enum) {
704 # Create subtree items:
705 defined($enum{$enum_name{$enum}}) or die("Enum $enum not found");
706  
707 # Wireshark does not allow FT_BYTES or BASE_NONE to have an enum
708 $ft =~ s/FT_BYTES/FT_UINT8/;
709 $base =~ s/BASE_NONE/BASE_DEC/;
710  
711 my $bitsize = $info->{'size'} * 8;
712  
713 my $bit = $enum{$enum_name{$enum}}{bit};
714 for my $val (sort { $a <=> $b } keys %$bit) {
715 my $itemname = $$bit{$val};
716 my $item = $regname . '_mask_' . $itemname;
717 my $itemhuman = $humanname . '.' . $itemname;
718 my $bitshift = "1U << $val";
719  
720 say $decl "static int $item = -1;";
721 say $reg "{ &$item, { \"$itemname\", \"$itemhuman\", FT_BOOLEAN, $bitsize, NULL, $bitshift, NULL, HFILL }},";
722 }
723 }
724  
725 print $decl "static int $regname = -1;\n";
726 if ($e->name() eq 'list' and $info->{'size'} > 1) {
727 print $reg "{ &$regname, { \"$fieldname\", \"$humanname\", FT_NONE, BASE_NONE, NULL, 0, NULL, HFILL }},\n";
728 $regname .= '_item';
729 print $decl "static int $regname = -1;\n";
730 }
731 print $reg "{ &$regname, { \"$fieldname\", \"$humanname\", $ft, $base, $vals, 0, NULL, HFILL }},\n";
732  
733 if ($refref->{sumof}{$fieldname}) {
734 print $impl $indent."int sumof_$fieldname = 0;\n";
735 }
736  
737 if ($e->name() eq 'field') {
738 if ($refref->{field}{$fieldname} and get_simple_info($type)) {
739 # Pre-declare variable
740 if ($ft eq 'FT_FLOAT') {
741 print $impl $indent."gfloat f_$fieldname;\n";
742 } elsif ($ft eq 'FT_DOUBLE') {
743 print $impl $indent."gdouble f_$fieldname;\n";
744 } elsif ($ft eq 'FT_INT64' or $ft eq 'FT_UINT64') {
745 print $impl $indent."gint64 f_$fieldname;\n";
746 } else {
747 print $impl $indent."int f_$fieldname;\n";
748 }
749 }
750 }
751 }
752  
753 sub dissect_element($$$$$;$$);
754  
755 sub dissect_element($$$$$;$$)
756 {
757 my $e = shift;
758 my $varpat = shift;
759 my $humanpat = shift;
760 my $length = shift;
761 my $refref = shift;
762 my $adjustlength = shift;
763 my $indent = shift // ' ' x 4;
764  
765 given ($e->name()) {
766 when ('pad') {
767 my $bytes = $e->att('bytes');
768 my $align = $e->att('align');
769 if (defined $bytes) {
770 print $impl $indent."UNUSED($bytes);\n";
771 $length += $bytes;
772 } else {
773 say $impl $indent.'if (*offsetp % '.$align.') {';
774 say $impl $indent." UNUSED($align - *offsetp % $align);";
775 say $impl $indent."}";
776 if ($length % $align != 0) {
777 $length += $align - $length % $align;
778 }
779 if ($adjustlength) {
780 say $impl $indent.'length = ((length + '.($align-1).') & ~'.($align-1).');';
781 }
782 }
783 }
784 when ('field') {
785 my $fieldname = $e->att('name');
786 my $regname = 'hf_x11_'.sprintf ($varpat, $fieldname);
787 my $type = $e->att('type');
788  
789 if (get_simple_info($type)) {
790 my $info = get_simple_info($type);
791 my $size = $info->{'size'};
792 my $encoding = $info->{'encoding'};
793 my $get = $info->{'get'};
794  
795 if ($e->att('enum') // $e->att('altenum')) {
796 my $fieldsize = $size * 8;
797 print $impl $indent;
798 if ($refref->{field}{$fieldname}) {
799 print $impl "f_$fieldname = ";
800 }
801 say $impl "field$fieldsize(tvb, offsetp, t, $regname, byte_order);";
802 } elsif ($e->att('mask')) {
803 if ($refref->{field}{$fieldname}) {
804 say $impl $indent."f_$fieldname = $get(tvb, *offsetp);";
805 }
806 say $impl $indent."{";
807 say $impl $indent." proto_item *ti = proto_tree_add_item(t, $regname, tvb, *offsetp, $size, $encoding);";
808 say $impl $indent." proto_tree *bitmask_tree = proto_item_add_subtree(ti, ett_x11_rectangle);";
809  
810 my $bytesize = $info->{'size'};
811 my $byteencoding = $info->{'encoding'};
812 my $bit = $enum{$enum_name{$e->att('mask')}}{bit};
813 for my $val (sort { $a <=> $b } keys %$bit) {
814 my $item = $regname . '_mask_' . $$bit{$val};
815  
816 say $impl "$indent proto_tree_add_item(bitmask_tree, $item, tvb, *offsetp, $bytesize, $byteencoding);";
817 }
818  
819 say $impl $indent."}";
820 say $impl $indent."*offsetp += $size;";
821 } else {
822 if ($refref->{field}{$fieldname}) {
823 say $impl $indent."f_$fieldname = $get(tvb, *offsetp);";
824 }
825 print $impl $indent."proto_tree_add_item(t, $regname, tvb, *offsetp, $size, $encoding);\n";
826 print $impl $indent."*offsetp += $size;\n";
827 }
828 $length += $size;
829 } elsif (get_struct_info($type)) {
830 # TODO: variable-lengths (when $info->{'size'} == 0 )
831 my $info = get_struct_info($type);
832 $length += $info->{'size'};
833 print $impl $indent."struct_$info->{'name'}(tvb, offsetp, t, byte_order, 1);\n";
834 } else {
835 die ("Unrecognized type: $type\n");
836 }
837 }
838 when ('list') {
839 my $fieldname = $e->att('name');
840 my $regname = 'hf_x11_'.sprintf ($varpat, $fieldname);
841 my $type = $e->att('type');
842  
843 my $info = getinfo($type);
844 my $lencalc = "(length - $length) / $info->{'size'}";
845 my $lentype = $e->first_child();
846 if (defined $lentype) {
847 given ($lentype->name()) {
848 when ('value') { $lencalc = $lentype->text(); }
849 when ('fieldref') { $lencalc = 'f_'.$lentype->text(); }
850 when ('paramref') { $lencalc = 'p_'.$lentype->text(); }
851 when ('op') { $lencalc = get_op($lentype); }
852 when (['unop','popcount']) { $lencalc = get_unop($lentype); }
853 when ('sumof') { $lencalc = 'sumof_'.$lentype->att('ref'); }
854 }
855 }
856  
857 if (get_simple_info($type)) {
858 my $list = $info->{'list'};
859 my $size = $info->{'size'};
860 $regname .= ", $regname".'_item' if ($size > 1);
861  
862 if ($refref->{sumof}{$fieldname}) {
863 my $get = $info->{'get'};
864 say $impl $indent."{";
865 say $impl $indent." int i;";
866 say $impl $indent." for (i = 0; i < $lencalc; i++) {";
867 say $impl $indent." sumof_$fieldname += $get(tvb, *offsetp + i * $size);";
868 say $impl $indent." }";
869 say $impl $indent."}";
870 }
871  
872 print $impl $indent."$list(tvb, offsetp, t, $regname, $lencalc, byte_order);\n";
873 } elsif (get_struct_info($type)) {
874 my $si = get_struct_info($type);
875 my $prefs = "";
876 foreach my $pref (sort keys %{$si->{paramref}}) {
877 $prefs .= ", f_$pref";
878 }
879  
880 print $impl $indent."struct_$info->{'name'}(tvb, offsetp, t, byte_order, $lencalc$prefs);\n";
881 } else {
882 die ("Unrecognized type: $type\n");
883 }
884  
885 if ($adjustlength && defined($lentype)) {
886 # Some requests end with a list of unspecified length
887 # Adjust the length field here so that the next $lencalc will be accurate
888 say $impl $indent."length -= $lencalc * $info->{'size'};";
889 }
890 }
891 when ('switch') {
892 my $switchtype = $e->first_child() or die("Switch element not defined");
893  
894 my $switchon = get_ref($switchtype, {});
895 my @elements = $e->children(qr/(bit)?case/);
896 for my $case (@elements) {
897 my @refs = $case->children('enumref');
898 my @test;
899 my $fieldname;
900 foreach my $ref (@refs) {
901 my $enum_ref = $ref->att('ref');
902 my $field = $ref->text();
903 $fieldname //= $field; # Use first named field
904 if ($case->name() eq 'bitcase') {
905 my $bit = $enum{$enum_name{$enum_ref}}{rbit}{$field};
906 if (! defined($bit)) {
907 for my $foo (keys %{$enum{$enum_name{$enum_ref}}{rbit}}) { say "'$foo'"; }
908 die ("Field '$field' not found in '$enum_ref'");
909 }
910 push @test , "$switchon & (1U << $bit)";
911 } else {
912 my $val = $enum{$enum_name{$enum_ref}}{rvalue}{$field};
913 if (! defined($val)) {
914 for my $foo (keys %{$enum{$enum_name{$enum_ref}}{rvalue}}) { say "'$foo'"; }
915 die ("Field '$field' not found in '$enum_ref'");
916 }
917 push @test , "$switchon == $val";
918 }
919 }
920  
921 if (@test > 1) {
922 # We have more than one conditional, add parentheses to them.
923 # We don't add parentheses to all the conditionals because
924 # clang complains about the extra parens if you do "if ((x == y))".
925 my @tests_with_parens;
926 foreach my $conditional (@test) {
927 push @tests_with_parens, "($conditional)";
928 }
929  
930 @test = @tests_with_parens;
931 }
932  
933 my $list = join ' || ', @test;
934 say $impl $indent."if ($list) {";
935  
936 my $vp = $varpat;
937 my $hp = $humanpat;
938  
939 $vp =~ s/%s/${fieldname}_%s/;
940 $hp =~ s/%s/${fieldname}.%s/;
941  
942 my @sub_elements = $case->children(qr/pad|field|list|switch/);
943  
944 my $subref = { field => {}, sumof => {} };
945 foreach my $sub_e (@sub_elements) {
946 reference_elements($sub_e, $subref);
947 }
948 foreach my $sub_e (@sub_elements) {
949 register_element($sub_e, $vp, $hp, $subref, $indent . ' ');
950 }
951 foreach my $sub_e (@sub_elements) {
952 $length = dissect_element($sub_e, $vp, $hp, $length, $subref, $adjustlength, $indent . ' ');
953 }
954  
955 say $impl $indent."}";
956 }
957 }
958 default { die "Unknown field type: $_\n"; }
959 }
960 return $length;
961 }
962  
963 sub struct {
964 my ($t, $elt) = @_;
965 my $name = $elt->att('name');
966 my $qualname = qualname($name);
967 $type_name{$name} = $qualname;
968  
969 if (defined $struct{$qualname}) {
970 $t->purge;
971 return;
972 }
973  
974 my @elements = $elt->children(qr/pad|field|list|switch/);
975  
976 print(" - Struct $name\n");
977  
978 $name = $qualname;
979 $name =~ s/:/_/;
980  
981 my %refs;
982 my %paramrefs;
983 my $size = 0;
984 my $dynamic = 0;
985 my $needi = 0;
986 # Find struct size
987 foreach my $e (@elements) {
988 my $count;
989 $count = 1;
990 given ($e->name()) {
991 when ('pad') {
992 my $bytes = $e->att('bytes');
993 my $align = $e->att('align');
994 if (defined $bytes) {
995 $size += $bytes;
996 next;
997 }
998 if (!$dynamic) {
999 if ($size % $align) {
1000 $size += $align - $size % $align;
1001 }
1002 }
1003 next;
1004 }
1005 when ('list') {
1006 my $type = $e->att('type');
1007 my $info = getinfo($type);
1008  
1009 $needi = 1 if ($info->{'size'} == 0);
1010  
1011 my $value = $e->first_child();
1012 given($value->name()) {
1013 when ('fieldref') {
1014 $refs{$value->text()} = 1;
1015 $count = 0;
1016 $dynamic = 1;
1017 }
1018 when ('paramref') {
1019 $paramrefs{$value->text()} = $value->att('type');
1020 $count = 0;
1021 $dynamic = 1;
1022 }
1023 when ('op') {
1024 get_op($value, \%refs);
1025 $count = 0;
1026 $dynamic = 1;
1027 }
1028 when (['unop','popcount']) {
1029 get_unop($value, \%refs);
1030 $count = 0;
1031 $dynamic = 1;
1032 }
1033 when ('value') {
1034 $count = $value->text();
1035 }
1036 default { die("Invalid list size $_\n"); }
1037 }
1038 }
1039 when ('field') { }
1040 when ('switch') {
1041 $dynamic = 1;
1042 next;
1043 }
1044 default { die("unrecognized field: $_\n"); }
1045 }
1046  
1047 my $type = $e->att('type');
1048 my $info = getinfo($type);
1049  
1050 $size += $info->{'size'} * $count;
1051 }
1052  
1053 my $prefs = "";
1054  
1055 if ($dynamic) {
1056 $size = 0;
1057  
1058 foreach my $pref (sort keys %paramrefs) {
1059 $prefs .= ", int p_$pref";
1060 }
1061  
1062 print $impl <<eot
1063  
1064 static int struct_size_$name(tvbuff_t *tvb _U_, int *offsetp _U_, guint byte_order _U_$prefs)
1065 {
1066 int size = 0;
1067 eot
1068 ;
1069 say $impl ' int i, off;' if ($needi);
1070  
1071 foreach my $ref (sort keys %refs) {
1072 say $impl " int f_$ref;";
1073 }
1074  
1075 foreach my $e (@elements) {
1076 my $count;
1077 $count = 1;
1078  
1079 my $type = $e->att('type') // '';
1080 my $info = getinfo($type);
1081  
1082 given ($e->name()) {
1083 when ('pad') {
1084 my $bytes = $e->att('bytes');
1085 my $align = $e->att('align');
1086 if (defined $bytes) {
1087 $size += $bytes;
1088 } else {
1089 say $impl ' size = (size + '.($align-1).') & ~'.($align-1).';';
1090 }
1091 }
1092 when ('list') {
1093 my $len = $e->first_child();
1094 my $infosize = $info->{'size'};
1095 my $sizemul;
1096  
1097 given ($len->name()) {
1098 when ('op') { $sizemul = get_op($len, \%refs); }
1099 when (['unop','popcount']) { $sizemul = get_unop($len, \%refs); }
1100 when ('fieldref') { $sizemul = 'f_'.$len->text(); }
1101 when ('paramref') { $sizemul = 'p_'.$len->text(); }
1102 when ('value') {
1103 if ($infosize) {
1104 $size += $infosize * $len->text();
1105 } else {
1106 $sizemul = $len->text();
1107 }
1108 }
1109 default { die "Invalid list size: $_\n"; }
1110 }
1111 if (defined $sizemul) {
1112 if ($infosize) {
1113 say $impl " size += $sizemul * $infosize;";
1114 } else {
1115 say $impl " for (i = 0; i < $sizemul; i++) {";
1116 say $impl " off = (*offsetp) + size + $size;";
1117 say $impl " size += struct_size_$info->{name}(tvb, &off, byte_order);";
1118 say $impl ' }';
1119 }
1120 }
1121 }
1122 when ('field') {
1123 my $fname = $e->att('name');
1124 if (defined($refs{$fname})) {
1125 say $impl " f_$fname = $info->{'get'}(tvb, *offsetp + size + $size);";
1126 }
1127 $size += $info->{'size'};
1128 }
1129 }
1130 }
1131 say $impl " return size + $size;";
1132 say $impl '}';
1133 $size = 0; # 0 means "dynamic calcuation required"
1134 }
1135  
1136 print $decl "static int hf_x11_struct_$name = -1;\n";
1137 print $reg "{ &hf_x11_struct_$name, { \"$name\", \"x11.struct.$name\", FT_NONE, BASE_NONE, NULL, 0, NULL, HFILL }},\n";
1138  
1139 print $impl <<eot
1140  
1141 static void struct_$name(tvbuff_t *tvb, int *offsetp, proto_tree *root, guint byte_order _U_, int count$prefs)
1142 {
1143 int i;
1144 for (i = 0; i < count; i++) {
1145 proto_item *item;
1146 proto_tree *t;
1147 eot
1148 ;
1149  
1150 my $varpat = 'struct_'.$name.'_%s';
1151 my $humanpat = "struct.$name.%s";
1152 my $refs = { field => {}, sumof => {} };
1153  
1154 foreach my $e (@elements) {
1155 reference_elements($e, $refs);
1156 }
1157 foreach my $e (@elements) {
1158 register_element($e, $varpat, $humanpat, $refs, " ");
1159 }
1160  
1161 $prefs = "";
1162 foreach my $pref (sort keys %paramrefs) {
1163 $prefs .= ", p_$pref";
1164 }
1165  
1166 my $sizecalc = $size;
1167 $size or $sizecalc = "struct_size_$name(tvb, offsetp, byte_order$prefs)";
1168  
1169 print $impl <<eot
1170  
1171 item = proto_tree_add_item(root, hf_x11_struct_$name, tvb, *offsetp, $sizecalc, ENC_NA);
1172 t = proto_item_add_subtree(item, ett_x11_rectangle);
1173 eot
1174 ;
1175 my $length = 0;
1176 foreach my $e (@elements) {
1177 $length = dissect_element($e, $varpat, $humanpat, $length, $refs, 0, " ");
1178 }
1179  
1180 print $impl " }\n}\n";
1181 $struct{$qualname} = { size => $size, name => $name, paramref => \%paramrefs };
1182 $t->purge;
1183 }
1184  
1185 sub union {
1186 # TODO proper dissection
1187 #
1188 # Right now, the only extension to use a union is randr.
1189 # for now, punt.
1190 my ($t, $elt) = @_;
1191 my $name = $elt->att('name');
1192 my $qualname = qualname($name);
1193 $type_name{$name} = $qualname;
1194  
1195 if (defined $struct{$qualname}) {
1196 $t->purge;
1197 return;
1198 }
1199  
1200 my @elements = $elt->children(qr/field/);
1201 my @sizes;
1202  
1203 print(" - Union $name\n");
1204  
1205 $name = $qualname;
1206 $name =~ s/:/_/;
1207  
1208 # Find union size
1209 foreach my $e (@elements) {
1210 my $type = $e->att('type');
1211 my $info = getinfo($type);
1212  
1213 $info->{'size'} > 0 or die ("Error: Union containing variable sized struct $type\n");
1214 push @sizes, $info->{'size'};
1215 }
1216 @sizes = sort {$b <=> $a} @sizes;
1217 my $size = $sizes[0];
1218  
1219 print $decl "static int hf_x11_union_$name = -1;\n";
1220 print $reg "{ &hf_x11_union_$name, { \"$name\", \"x11.union.$name\", FT_NONE, BASE_NONE, NULL, 0, NULL, HFILL }},\n";
1221  
1222 print $impl <<eot
1223  
1224 static void struct_$name(tvbuff_t *tvb, int *offsetp, proto_tree *root, guint byte_order, int count)
1225 {
1226 int i;
1227 int base = *offsetp;
1228 for (i = 0; i < count; i++) {
1229 proto_item *item;
1230 proto_tree *t;
1231 eot
1232 ;
1233  
1234 my $varpat = 'union_'.$name.'_%s';
1235 my $humanpat = "union.$name.%s";
1236 my $refs = { field => {}, sumof => {} };
1237  
1238 foreach my $e (@elements) {
1239 reference_elements($e, $refs);
1240 }
1241 foreach my $e (@elements) {
1242 register_element($e, $varpat, $humanpat, $refs, " ");
1243 }
1244  
1245 print $impl <<eot
1246 item = proto_tree_add_item(root, hf_x11_union_$name, tvb, base, $size, ENC_NA);
1247 t = proto_item_add_subtree(item, ett_x11_rectangle);
1248  
1249 eot
1250 ;
1251  
1252 foreach my $e (@elements) {
1253 say $impl ' *offsetp = base;';
1254 dissect_element($e, $varpat, $humanpat, 0, $refs, 0, " ");
1255 }
1256 say $impl " base += $size;";
1257 say $impl ' }';
1258 say $impl ' *offsetp = base;';
1259 say $impl '}';
1260  
1261 $struct{$qualname} = { size => $size, name => $name };
1262 $t->purge;
1263 }
1264  
1265 sub enum {
1266 my ($t, $elt) = @_;
1267 my $name = $elt->att('name');
1268 my $fullname = $incname[0].'_'.$name;
1269  
1270 $enum_name{$name} = $fullname;
1271 $enum_name{$incname[0].':'.$name} = $fullname;
1272  
1273 if (defined $enum{$fullname}) {
1274 $t->purge;
1275 return;
1276 }
1277  
1278 my @elements = $elt->children('item');
1279  
1280 print(" - Enum $name\n");
1281  
1282 my $value = {};
1283 my $bit = {};
1284 my $rvalue = {};
1285 my $rbit = {};
1286 $enum{$fullname} = { value => $value, bit => $bit, rbit => $rbit, rvalue => $rvalue };
1287  
1288 my $nextvalue = 0;
1289  
1290 foreach my $e (@elements) {
1291 my $n = $e->att('name');
1292 my $valtype = $e->first_child(qr/value|bit/);
1293 if (defined $valtype) {
1294 my $val = int($valtype->text());
1295 given ($valtype->name()) {
1296 when ('value') {
1297 $$value{$val} = $n;
1298 $$rvalue{$n} = $val;
1299 $nextvalue = $val + 1;
1300  
1301 # Ugly hack to support (temporary, hopefully) ugly
1302 # hack in xinput:ChangeDeviceProperty
1303 # Register certain values as bits also
1304 given ($val) {
1305 when (8) {
1306 $$bit{'3'} = $n;
1307 $$rbit{$n} = 3;
1308 }
1309 when (16) {
1310 $$bit{'4'} = $n;
1311 $$rbit{$n} = 4;
1312 }
1313 when (32) {
1314 $$bit{'5'} = $n;
1315 $$rbit{$n} = 5;
1316 }
1317 }
1318 }
1319 when ('bit') {
1320 $$bit{$val} = $n;
1321 $$rbit{$n} = $val;
1322 }
1323 }
1324 } else {
1325 $$value{$nextvalue} = $n;
1326 $nextvalue++;
1327 }
1328 }
1329  
1330 $t->purge;
1331 }
1332  
1333 sub request {
1334 my ($t, $elt) = @_;
1335 my $name = $elt->att('name');
1336  
1337 print(" - Request $name\n");
1338 $request{$elt->att('opcode')} = $name;
1339  
1340 my $length = 4;
1341 my @elements = $elt->children(qr/pad|field|list|switch/);
1342  
1343 # Wireshark defines _U_ to mean "Unused" (compiler specific define)
1344 if (!@elements) {
1345 print $impl <<eot
1346  
1347 static void $header$name(tvbuff_t *tvb _U_, packet_info *pinfo _U_, int *offsetp _U_, proto_tree *t _U_, guint byte_order _U_, int length _U_)
1348 {
1349 eot
1350 ;
1351 } else {
1352 print $impl <<eot
1353  
1354 static void $header$name(tvbuff_t *tvb, packet_info *pinfo _U_, int *offsetp, proto_tree *t, guint byte_order, int length _U_)
1355 {
1356 eot
1357 ;
1358 }
1359 my $varpat = $header.'_'.$name.'_%s';
1360 my $humanpat = "$header.$name.%s";
1361 my $refs = { field => {}, sumof => {} };
1362  
1363 foreach my $e (@elements) {
1364 reference_elements($e, $refs);
1365 }
1366 foreach my $e (@elements) {
1367 register_element($e, $varpat, $humanpat, $refs);
1368 }
1369  
1370 foreach my $e (@elements) {
1371 if ($e->name() eq 'list' && $name eq 'Render' && $e->att('name') eq 'data' && -e "$mesadir/gl_API.xml") {
1372 # Special case: Use mesa-generated dissector for 'data'
1373 print $impl " dispatch_glx_render(tvb, pinfo, offsetp, t, byte_order, (length - $length));\n";
1374 } else {
1375 $length = dissect_element($e, $varpat, $humanpat, $length, $refs, 1);
1376 }
1377 }
1378  
1379 say $impl '}';
1380  
1381 my $reply = $elt->first_child('reply');
1382 if ($reply) {
1383 $reply{$elt->att('opcode')} = $name;
1384  
1385 $varpat = $header.'_'.$name.'_reply_%s';
1386 $humanpat = "$header.$name.reply.%s";
1387  
1388 @elements = $reply->children(qr/pad|field|list|switch/);
1389  
1390 # Wireshark defines _U_ to mean "Unused" (compiler specific define)
1391 if (!@elements) {
1392 say $impl "static void $header$name"."_Reply(tvbuff_t *tvb _U_, packet_info *pinfo, int *offsetp _U_, proto_tree *t _U_, guint byte_order _U_)\n{";
1393 } else {
1394 say $impl "static void $header$name"."_Reply(tvbuff_t *tvb, packet_info *pinfo, int *offsetp, proto_tree *t, guint byte_order)\n{";
1395 }
1396 say $impl ' int sequence_number;' if (@elements);
1397  
1398 my $refs = { field => {}, sumof => {} };
1399 foreach my $e (@elements) {
1400 reference_elements($e, $refs);
1401 }
1402  
1403 say $impl ' int f_length;' if ($refs->{field}{'length'});
1404 say $impl ' int length;' if ($refs->{length});
1405 foreach my $e (@elements) {
1406 register_element($e, $varpat, $humanpat, $refs);
1407 }
1408  
1409 say $impl '';
1410 say $impl ' col_append_fstr(pinfo->cinfo, COL_INFO, "-'.$name.'");';
1411 say $impl '';
1412 say $impl ' REPLY(reply);';
1413  
1414 my $first = 1;
1415 my $length = 1;
1416 foreach my $e (@elements) {
1417 $length = dissect_element($e, $varpat, $humanpat, $length, $refs);
1418 if ($first) {
1419 $first = 0;
1420 say $impl ' sequence_number = VALUE16(tvb, *offsetp);';
1421 say $impl ' proto_tree_add_uint_format(t, hf_x11_reply_sequencenumber, tvb, *offsetp, 2, sequence_number,';
1422 say $impl ' "sequencenumber: %d ('.$header.'-'.$name.')", sequence_number);';
1423 say $impl ' *offsetp += 2;';
1424  
1425 if ($refs->{field}{length}) {
1426 say $impl ' f_length = VALUE32(tvb, *offsetp);';
1427 }
1428 if ($refs->{length}) {
1429 say $impl ' length = f_length * 4 + 32;';
1430 }
1431 say $impl ' proto_tree_add_item(t, hf_x11_replylength, tvb, *offsetp, 4, byte_order);';
1432 say $impl ' *offsetp += 4;';
1433  
1434 $length += 6;
1435 }
1436 }
1437  
1438 say $impl '}';
1439 }
1440 $t->purge;
1441 }
1442  
1443 sub defxid(@) {
1444 my $name;
1445 while ($name = shift) {
1446 my $qualname = qualname($name);
1447 $simpletype{$qualname} = { size => 4, encoding => 'byte_order', type => 'FT_UINT32', base => 'BASE_HEX', get => 'VALUE32', list => 'listOfCard32', };
1448 $type_name{$name} = $qualname;
1449 }
1450 }
1451  
1452 sub xidtype {
1453 my ($t, $elt) = @_;
1454 my $name = $elt->att('name');
1455  
1456 defxid($name);
1457  
1458 $t->purge;
1459 }
1460  
1461 sub typedef {
1462 my ($t, $elt) = @_;
1463 my $oldname = $elt->att('oldname');
1464 my $newname = $elt->att('newname');
1465 my $qualname = qualname($newname);
1466  
1467 # Duplicate the type
1468 my $info = get_simple_info($oldname);
1469 if ($info) {
1470 $simpletype{$qualname} = $info;
1471 } elsif ($info = get_struct_info($oldname)) {
1472 $struct{$qualname} = $info;
1473 } else {
1474 die ("$oldname not found while attempting to typedef $newname\n");
1475 }
1476 $type_name{$newname} = $qualname;
1477  
1478 $t->purge;
1479 }
1480  
1481 sub error {
1482 my ($t, $elt) = @_;
1483  
1484 my $number = $elt->att('number');
1485 if ($number >= 0) {
1486 my $name = $elt->att('name');
1487 print $error " \"$header-$name\",\n";
1488 }
1489  
1490 $t->purge;
1491 }
1492  
1493 sub event {
1494 my ($t, $elt) = @_;
1495  
1496 my $number = $elt->att('number');
1497 $number or return;
1498  
1499 my $name = $elt->att('name');
1500 my $xge = $elt->att('xge');
1501  
1502 if ($xge) {
1503 $genericevent{$number} = $name;
1504 } else {
1505 $event{$number} = $name;
1506 }
1507  
1508 my $length = 1;
1509 my @elements = $elt->children(qr/pad|field|list|switch/);
1510  
1511 # Wireshark defines _U_ to mean "Unused" (compiler specific define)
1512 if (!@elements) {
1513 if ($xge) {
1514 print $impl <<eot
1515  
1516 static void $header$name(tvbuff_t *tvb _U_, int length _U_, int *offsetp _U_, proto_tree *t _U_, guint byte_order _U_)
1517 {
1518 } else {
1519 print $impl <<eot
1520  
1521 static void $header$name(tvbuff_t *tvb _U_, int *offsetp _U_, proto_tree *t _U_, guint byte_order _U_)
1522 {
1523 eot
1524 ;
1525 }
1526 } else {
1527 if ($xge) {
1528 $length = 10;
1529 print $impl <<eot
1530  
1531 static void $header$name(tvbuff_t *tvb, int length _U_, int *offsetp, proto_tree *t, guint byte_order)
1532 {
1533 eot
1534 ;
1535 } else {
1536 print $impl <<eot
1537  
1538 static void $header$name(tvbuff_t *tvb, int *offsetp, proto_tree *t, guint byte_order)
1539 {
1540 eot
1541 ;
1542 }
1543 }
1544  
1545 my $varpat = $header.'_'.$name.'_%s';
1546 my $humanpat = "$header.$name.%s";
1547 my $refs = { field => {}, sumof => {} };
1548  
1549 foreach my $e (@elements) {
1550 reference_elements($e, $refs);
1551 }
1552 foreach my $e (@elements) {
1553 register_element($e, $varpat, $humanpat, $refs);
1554 }
1555  
1556 if ($xge) {
1557 say $impl " proto_tree_add_uint_format(t, hf_x11_minor_opcode, tvb, *offsetp, 2, $number,";
1558 say $impl " \"opcode: $name ($number)\");";
1559 foreach my $e (@elements) {
1560 $length = dissect_element($e, $varpat, $humanpat, $length, $refs);
1561 }
1562 } else {
1563 my $first = 1;
1564 foreach my $e (@elements) {
1565 $length = dissect_element($e, $varpat, $humanpat, $length, $refs);
1566 if ($first) {
1567 $first = 0;
1568 say $impl " CARD16(event_sequencenumber);";
1569 }
1570 }
1571 }
1572  
1573 say $impl "}\n";
1574  
1575 $t->purge;
1576 }
1577  
1578 sub include_start {
1579 my ($t, $elt) = @_;
1580 my $header = $elt->att('header');
1581 unshift @incname, $header;
1582 }
1583  
1584 sub include_end {
1585 shift @incname;
1586 }
1587  
1588 sub include
1589 {
1590 my ($t, $elt) = @_;
1591 my $include = $elt->text();
1592  
1593 print " - Import $include\n";
1594 my $xml = XML::Twig->new(
1595 start_tag_handlers => {
1596 'xcb' => \&include_start,
1597 },
1598 twig_roots => {
1599 'import' => \&include,
1600 'struct' => \&struct,
1601 'xidtype' => \&xidtype,
1602 'xidunion' => \&xidtype,
1603 'typedef' => \&typedef,
1604 'enum' => \&enum,
1605 },
1606 end_tag_handlers => {
1607 'xcb' => \&include_end,
1608 });
1609 $xml->parsefile("$srcdir/xcbproto/src/$include.xml") or die ("Cannot open $include.xml\n");
1610  
1611 $t->purge;
1612 }
1613  
1614  
1615 sub xcb_start {
1616 my ($t, $elt) = @_;
1617 $header = $elt->att('header');
1618 $extname = ($elt->att('extension-name') or $header);
1619 unshift @incname, $header;
1620  
1621 print("Extension $extname\n");
1622  
1623 undef %request;
1624 undef %genericevent;
1625 undef %event;
1626 undef %reply;
1627  
1628 %simpletype = ();
1629 %enum_name = ();
1630 %type_name = ();
1631  
1632 print $error "const char *$header"."_errors[] = {\n";
1633 }
1634  
1635 sub xcb {
1636 my ($t, $elt) = @_;
1637  
1638 my $xextname = $elt->att('extension-xname');
1639 my $lookup_name = $header . "_extension_minor";
1640 my $error_name = $header . "_errors";
1641 my $event_name = $header . "_events";
1642 my $genevent_name = 'NULL';
1643 my $reply_name = $header . "_replies";
1644  
1645 print $decl "static int hf_x11_$lookup_name = -1;\n\n";
1646  
1647 print $impl "static const value_string $lookup_name"."[] = {\n";
1648 foreach my $req (sort {$a <=> $b} keys %request) {
1649 print $impl " { $req, \"$request{$req}\" },\n";
1650 }
1651 print $impl " { 0, NULL }\n";
1652 print $impl "};\n";
1653  
1654 say $impl "const x11_event_info $event_name".'[] = {';
1655 foreach my $e (sort {$a <=> $b} keys %event) {
1656 say $impl " { \"$header-$event{$e}\", $header$event{$e} },";
1657 }
1658 say $impl ' { NULL, NULL }';
1659 say $impl '};';
1660  
1661 if (%genericevent) {
1662 $genevent_name = $header.'_generic_events';
1663 say $impl 'static const x11_generic_event_info '.$genevent_name.'[] = {';
1664  
1665 for my $val (sort { $a <=> $b } keys %genericevent) {
1666 say $impl sprintf(" { %3d, %s },", $val, $header.$genericevent{$val});
1667 }
1668 say $impl sprintf(" { %3d, NULL },", 0);
1669 say $impl '};';
1670 say $impl '';
1671 }
1672  
1673 print $impl "static x11_reply_info $reply_name"."[] = {\n";
1674 foreach my $e (sort {$a <=> $b} keys %reply) {
1675 print $impl " { $e, $header$reply{$e}_Reply },\n";
1676 }
1677 print $impl " { 0, NULL }\n";
1678 print $impl "};\n";
1679  
1680 print $reg "{ &hf_x11_$lookup_name, { \"extension-minor\", \"x11.extension-minor\", FT_UINT8, BASE_DEC, VALS($lookup_name), 0, \"minor opcode\", HFILL }},\n\n";
1681  
1682 print $impl <<eot
1683  
1684 static void dispatch_$header(tvbuff_t *tvb, packet_info *pinfo, int *offsetp, proto_tree *t, guint byte_order)
1685 {
1686 int minor, length;
1687 minor = CARD8($lookup_name);
1688 length = REQUEST_LENGTH();
1689  
1690 col_append_fstr(pinfo->cinfo, COL_INFO, "-%s",
1691 val_to_str(minor, $lookup_name,
1692 "<Unknown opcode %d>"));
1693 switch (minor) {
1694 eot
1695 ;
1696  
1697 foreach my $req (sort {$a <=> $b} keys %request) {
1698 print $impl " case $req:\n";
1699 print $impl " $header$request{$req}(tvb, pinfo, offsetp, t, byte_order, length);\n";
1700 print $impl " break;\n";
1701 }
1702 say $impl " /* No need for a default case here, since Unknown is printed above,";
1703 say $impl " and UNDECODED() is taken care of by dissect_x11_request */";
1704 print $impl " }\n}\n";
1705 print $impl <<eot
1706  
1707 static void register_$header(void)
1708 {
1709 set_handler("$xextname", dispatch_$header, $error_name, $event_name, $genevent_name, $reply_name);
1710 }
1711 eot
1712 ;
1713  
1714 print $error " NULL\n};\n\n";
1715  
1716 push @register, $header;
1717 }
1718  
1719 sub find_version {
1720 #my $git = `which git`;
1721 #chomp($git);
1722 #-x $git or return 'unknown';
1723  
1724 my $lib = shift;
1725 # this will generate an error on stderr if git isn't in our $PATH
1726 # but that's OK. The version is still set to 'unknown' in that case
1727 # and at least the operator could see it.
1728 my $ver = `git --git-dir=$lib/.git describe --tags`;
1729 $ver //= 'unknown';
1730 chomp $ver;
1731 return $ver;
1732 }
1733  
1734 sub add_generated_header {
1735 my ($out, $using) = @_;
1736 my $ver = find_version($using);
1737  
1738 $using = File::Spec->abs2rel ($using, $srcdir);
1739  
1740 print $out <<eot
1741 /* Do not modify this file. */
1742 /* It was automatically generated by $script_name
1743 using $using version $ver */
1744 eot
1745 ;
1746  
1747 # Add license text
1748 print $out <<eot
1749 /*
1750 * Copyright 2008, 2009, 2013, 2014 Open Text Corporation <pharris[AT]opentext.com>
1751 *
1752 * Wireshark - Network traffic analyzer
1753 * By Gerald Combs <gerald[AT]wireshark.org>
1754 * Copyright 1998 Gerald Combs
1755 *
1756 * This program is free software; you can redistribute it and/or modify
1757 * it under the terms of the GNU General Public License as published by
1758 * the Free Software Foundation; either version 2 of the License, or
1759 * (at your option) any later version.
1760 *
1761 * This program is distributed in the hope that it will be useful,
1762 * but WITHOUT ANY WARRANTY; without even the implied warranty of
1763 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1764 * GNU General Public License for more details.
1765 *
1766 * You should have received a copy of the GNU General Public License along
1767 * with this program; if not, write to the Free Software Foundation, Inc.,
1768 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
1769 */
1770  
1771 eot
1772 ;
1773 }
1774  
1775 # initialize core X11 protocol
1776 # Do this in the Makefile now
1777 #system('./process-x11-fields.pl < x11-fields');
1778  
1779 # Extension implementation
1780 $impl = new IO::File "> $srcdir/x11-extension-implementation.h"
1781 or die ("Cannot open $srcdir/x11-extension-implementation.h for writing\n");
1782 $error = new IO::File "> $srcdir/x11-extension-errors.h"
1783 or die ("Cannot open $srcdir/x11-extension-errors.h for writing\n");
1784  
1785 add_generated_header($impl, $srcdir . '/xcbproto');
1786 add_generated_header($error, $srcdir . '/xcbproto');
1787  
1788 # Open the files generated by process-x11-fields.pl for appending
1789 $reg = new IO::File ">> $srcdir/x11-register-info.h"
1790 or die ("Cannot open $srcdir/x11-register-info.h for appending\n");
1791 $decl = new IO::File ">> $srcdir/x11-declarations.h"
1792 or die ("Cannot open $srcdir/x11-declarations.h for appending\n");
1793  
1794 print $reg "\n/* Generated by $script_name below this line */\n";
1795 print $decl "\n/* Generated by $script_name below this line */\n";
1796  
1797 # Mesa for glRender
1798 if (-e "$mesadir/gl_API.xml") {
1799 $enum = new IO::File "> $srcdir/x11-glx-render-enum.h"
1800 or die ("Cannot open $srcdir/x11-glx-render-enum.h for writing\n");
1801 add_generated_header($enum, $srcdir . '/mesa');
1802 print $enum "static const value_string mesa_enum[] = {\n";
1803 print $impl '#include "x11-glx-render-enum.h"'."\n\n";
1804  
1805 print("Mesa glRender:\n");
1806 $header = "glx_render";
1807  
1808 my $xml = XML::Twig->new(
1809 start_tag_handlers => {
1810 'category' => \&mesa_category_start,
1811 },
1812 twig_roots => {
1813 'category' => \&mesa_category,
1814 'enum' => \&mesa_enum,
1815 'type' => \&mesa_type,
1816 'function' => \&mesa_function,
1817 });
1818 $xml->parsefile("$mesadir/gl_API.xml") or die ("Cannot open gl_API\n");
1819  
1820 print $enum " { 0, NULL }\n";
1821 print $enum "};\n";
1822 $enum->close();
1823  
1824 print $decl "static int hf_x11_glx_render_op_name = -1;\n\n";
1825  
1826 print $impl "static const value_string glx_render_op_name"."[] = {\n";
1827 foreach my $req (sort {$a <=> $b} keys %request) {
1828 print $impl " { $req, \"gl$request{$req}\" },\n";
1829 }
1830 print $impl " { 0, NULL }\n";
1831 print $impl "};\n";
1832  
1833 print $reg "{ &hf_x11_glx_render_op_name, { \"render op\", \"x11.glx.render.op\", FT_UINT16, BASE_DEC, VALS(glx_render_op_name), 0, NULL, HFILL }},\n\n";
1834  
1835 # Uses ett_x11_list_of_rectangle, since I am unable to see how the subtree type matters.
1836 print $impl <<eot
1837  
1838 static void dispatch_glx_render(tvbuff_t *tvb, packet_info *pinfo, int *offsetp, proto_tree *t, guint byte_order, int length)
1839 {
1840 while (length >= 4) {
1841 guint32 op, len;
1842 int next;
1843 proto_item *ti;
1844 proto_tree *tt;
1845  
1846 len = VALUE16(tvb, *offsetp);
1847  
1848 op = VALUE16(tvb, *offsetp + 2);
1849 ti = proto_tree_add_uint(t, hf_x11_glx_render_op_name, tvb, *offsetp, len, op);
1850  
1851 tt = proto_item_add_subtree(ti, ett_x11_list_of_rectangle);
1852  
1853 ti = proto_tree_add_item(tt, hf_x11_request_length, tvb, *offsetp, 2, byte_order);
1854 *offsetp += 2;
1855 proto_tree_add_item(tt, hf_x11_glx_render_op_name, tvb, *offsetp, 2, byte_order);
1856 *offsetp += 2;
1857  
1858 if (len < 4) {
1859 expert_add_info(pinfo, ti, &ei_x11_request_length);
1860 /* Eat the rest of the packet, mark it undecoded */
1861 len = length;
1862 op = -1;
1863 }
1864 len -= 4;
1865  
1866 next = *offsetp + len;
1867  
1868 switch (op) {
1869 eot
1870 ;
1871 foreach my $req (sort {$a <=> $b} keys %request) {
1872 print $impl " case $req:\n";
1873 print $impl " mesa_$request{$req}(tvb, offsetp, tt, byte_order, len);\n";
1874 print $impl " break;\n";
1875 }
1876 print $impl " default:\n";
1877 print $impl " proto_tree_add_item(tt, hf_x11_undecoded, tvb, *offsetp, len, ENC_NA);\n";
1878 print $impl " *offsetp += len;\n";
1879  
1880 print $impl " }\n";
1881 print $impl " if (*offsetp < next) {\n";
1882 print $impl " proto_tree_add_item(tt, hf_x11_unused, tvb, *offsetp, next - *offsetp, ENC_NA);\n";
1883 print $impl " *offsetp = next;\n";
1884 print $impl " }\n";
1885 print $impl " length -= (len + 4);\n";
1886 print $impl " }\n}\n";
1887 }
1888  
1889 $enum = new IO::File "> $srcdir/x11-enum.h"
1890 or die ("Cannot open $srcdir/x11-enum.h for writing\n");
1891 add_generated_header($enum, $srcdir . '/xcbproto');
1892 print $impl '#include "x11-enum.h"'."\n\n";
1893  
1894 # XCB
1895 foreach my $ext (@reslist) {
1896 my $xml = XML::Twig->new(
1897 start_tag_handlers => {
1898 'xcb' => \&xcb_start,
1899 },
1900 twig_roots => {
1901 'xcb' => \&xcb,
1902 'import' => \&include,
1903 'request' => \&request,
1904 'struct' => \&struct,
1905 'union' => \&union,
1906 'xidtype' => \&xidtype,
1907 'xidunion' => \&xidtype,
1908 'typedef' => \&typedef,
1909 'error' => \&error,
1910 'errorcopy' => \&error,
1911 'event' => \&event,
1912 'enum' => \&enum,
1913 });
1914 $xml->parsefile($ext) or die ("Cannot open $ext\n");
1915 }
1916  
1917 print $impl "static void register_x11_extensions(void)\n{\n";
1918 foreach my $reg (@register) {
1919 print $impl " register_$reg();\n";
1920 }
1921 print $impl "}\n";
1922  
1923 #
1924 # Editor modelines
1925 #
1926 # Local Variables:
1927 # c-basic-offset: 4
1928 # tab-width: 8
1929 # indent-tabs-mode: nil
1930 # End:
1931 #
1932 # ex: set shiftwidth=4 tabstop=8 expandtab:
1933 # :indentSize=4:tabSize=8:noTabs=true:
1934 #