Coverage Report

Created: 2026-11-12 07:01

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wireshark/epan/dissectors/packet-enttec.c
Line
Count
Source
1
/* packet-enttec.c
2
 * Routines for ENTTEC packet disassembly
3
 *
4
 * Copyright (c) 2003,2004 by Erwin Rol <erwin@erwinrol.com>
5
 *
6
 * Wireshark - Network traffic analyzer
7
 * By Gerald Combs <gerald@wireshark.org>
8
 * Copyright 1999 Gerald Combs
9
 *
10
 * SPDX-License-Identifier: GPL-2.0-or-later
11
 */
12
13
/* Include files */
14
15
#include "config.h"
16
17
#include <epan/packet.h>
18
#include <epan/prefs.h>
19
/*
20
 * See
21
 *
22
 *  http://www.enttec.com/docs/enttec_protocol.pdf
23
 */
24
25
/* Define UDP/TCP ports for ENTTEC */
26
27
16
#define UDP_PORT_ENTTEC 0x0D05 /* Not IANA registered */
28
16
#define TCP_PORT_ENTTEC 0x0D05 /* Not IANA registered */
29
30
31
0
#define ENTTEC_HEAD_ESPR 0x45535052
32
0
#define ENTTEC_HEAD_ESPP 0x45535050
33
0
#define ENTTEC_HEAD_ESAP 0x45534150
34
0
#define ENTTEC_HEAD_ESDD 0x45534444
35
1
#define ENTTEC_HEAD_ESNC 0x45534E43
36
0
#define ENTTEC_HEAD_ESZZ 0x45535A5A
37
38
static const value_string enttec_head_vals[] = {
39
  { ENTTEC_HEAD_ESPR, "Poll Reply" },
40
  { ENTTEC_HEAD_ESPP, "Poll" },
41
  { ENTTEC_HEAD_ESAP, "Ack/nAck" },
42
  { ENTTEC_HEAD_ESDD, "DMX Data" },
43
  { ENTTEC_HEAD_ESNC, "Config" },
44
  { ENTTEC_HEAD_ESZZ, "Reset" },
45
  { 0,      NULL }
46
};
47
48
0
#define ENTTEC_DATA_TYPE_DMX    0x01
49
#define ENTTEC_DATA_TYPE_CHAN_VAL 0x02
50
0
#define ENTTEC_DATA_TYPE_RLE    0x04
51
52
static const value_string enttec_data_type_vals[] = {
53
  { ENTTEC_DATA_TYPE_DMX,   "Uncompressed DMX" },
54
  { ENTTEC_DATA_TYPE_CHAN_VAL,  "Channel+Value" },
55
  { ENTTEC_DATA_TYPE_RLE,   "RLE Compressed DMX" },
56
  { 0,        NULL }
57
};
58
59
void proto_register_enttec(void);
60
void proto_reg_handoff_enttec(void);
61
62
static dissector_handle_t enttec_udp_handle, enttec_tcp_handle;
63
64
/* Define the enttec proto */
65
static int proto_enttec;
66
67
/* general */
68
static int hf_enttec_head;
69
70
/* poll */
71
static int hf_enttec_poll_type;
72
73
/* poll reply */
74
static int hf_enttec_poll_reply_mac;
75
static int hf_enttec_poll_reply_node_type;
76
static int hf_enttec_poll_reply_version;
77
static int hf_enttec_poll_reply_switch;
78
static int hf_enttec_poll_reply_name;
79
static int hf_enttec_poll_reply_option;
80
static int hf_enttec_poll_reply_tos;
81
static int hf_enttec_poll_reply_ttl;
82
83
/* dmx data */
84
static int hf_enttec_dmx_data_universe;
85
static int hf_enttec_dmx_data_start_code;
86
static int hf_enttec_dmx_data_type;
87
static int hf_enttec_dmx_data_size;
88
static int hf_enttec_dmx_data_data;
89
static int hf_enttec_dmx_data_data_filter;
90
static int hf_enttec_dmx_data_dmx_data;
91
92
/* Define the tree for enttec */
93
static int ett_enttec;
94
95
/*
96
 * Here are the global variables associated with the preferences
97
 * for enttec
98
 */
99
100
static int global_disp_chan_val_type;
101
static int global_disp_col_count = 16;
102
static int global_disp_chan_nr_type;
103
104
static int
105
dissect_enttec_poll_reply(tvbuff_t *tvb, unsigned offset, proto_tree *tree)
106
0
{
107
0
  proto_tree_add_item(tree, hf_enttec_poll_reply_mac, tvb,
108
0
          offset, 6, ENC_NA);
109
0
  offset += 6;
110
111
0
  proto_tree_add_item(tree, hf_enttec_poll_reply_node_type, tvb,
112
0
          offset, 2, ENC_BIG_ENDIAN);
113
0
  offset += 2;
114
115
0
  proto_tree_add_item(tree, hf_enttec_poll_reply_version, tvb,
116
0
          offset, 1, ENC_BIG_ENDIAN);
117
0
  offset += 1;
118
119
0
  proto_tree_add_item(tree, hf_enttec_poll_reply_switch, tvb,
120
0
          offset, 1, ENC_BIG_ENDIAN);
121
0
  offset += 1;
122
123
0
  proto_tree_add_item(tree, hf_enttec_poll_reply_name, tvb,
124
0
          offset, 10, ENC_ASCII);
125
0
  offset += 10;
126
127
0
  proto_tree_add_item(tree, hf_enttec_poll_reply_option, tvb,
128
0
          offset, 1, ENC_BIG_ENDIAN);
129
0
  offset += 1;
130
131
0
  proto_tree_add_item(tree, hf_enttec_poll_reply_tos, tvb,
132
0
          offset, 1, ENC_BIG_ENDIAN);
133
0
  offset += 1;
134
135
0
  proto_tree_add_item(tree, hf_enttec_poll_reply_ttl, tvb,
136
0
          offset, 1, ENC_BIG_ENDIAN);
137
0
  offset += 1;
138
139
  /* data */
140
141
0
  return offset;
142
0
}
143
144
static int
145
dissect_enttec_poll(tvbuff_t *tvb, unsigned offset, proto_tree *tree)
146
0
{
147
0
  proto_tree_add_item(tree, hf_enttec_poll_type, tvb,
148
0
          offset, 1, ENC_BIG_ENDIAN);
149
0
  offset += 1;
150
151
0
  return offset;
152
0
}
153
154
static int
155
dissect_enttec_ack(tvbuff_t *tvb _U_, unsigned offset, proto_tree *tree _U_)
156
0
{
157
158
0
  return offset;
159
0
}
160
161
static int
162
dissect_enttec_dmx_data(tvbuff_t *tvb, packet_info *pinfo, unsigned offset, proto_tree *tree)
163
0
{
164
0
  static const char* chan_format[] = {
165
0
    "%2u ",
166
0
    "%02x ",
167
0
    "%3u "
168
0
  };
169
0
  static const char* string_format[] = {
170
0
    "%03x: %s",
171
0
    "%3u: %s"
172
0
  };
173
174
0
  uint8_t *dmx_data = (uint8_t *)wmem_alloc(pinfo->pool, 512 * sizeof(uint8_t));
175
0
  uint16_t *dmx_data_offset = (uint16_t *)wmem_alloc(pinfo->pool, 513 * sizeof(uint16_t)); /* 1 extra for last offset */
176
0
  wmem_strbuf_t *dmx_epstr;
177
178
0
  proto_tree *hi,*si;
179
0
  proto_item *item;
180
0
  uint16_t length,r,c,row_count;
181
0
  uint8_t v,type,count;
182
0
  uint16_t ci,ui,i,start_offset,end_offset;
183
184
0
  proto_tree_add_item(tree, hf_enttec_dmx_data_universe, tvb,
185
0
          offset, 1, ENC_BIG_ENDIAN);
186
0
  offset += 1;
187
188
0
  proto_tree_add_item(tree, hf_enttec_dmx_data_start_code, tvb,
189
0
          offset, 1, ENC_BIG_ENDIAN);
190
0
  offset += 1;
191
192
0
  type = tvb_get_uint8(tvb, offset);
193
0
  proto_tree_add_item(tree, hf_enttec_dmx_data_type, tvb,
194
0
          offset, 1, ENC_BIG_ENDIAN);
195
0
  offset += 1;
196
197
0
  length = tvb_get_ntohs(tvb, offset);
198
0
  proto_tree_add_item(tree, hf_enttec_dmx_data_size, tvb,
199
0
          offset, 2, ENC_BIG_ENDIAN);
200
0
  offset += 2;
201
202
  /*
203
   * XXX - we should handle a too-long length better.
204
   */
205
0
  if (length > 512)
206
0
    length = 512;
207
208
0
  if (type == ENTTEC_DATA_TYPE_RLE) {
209
    /* uncompress the DMX data */
210
0
    ui = 0;
211
0
    ci = 0;
212
0
    while (ci < length && ui < 512) {
213
0
      v = tvb_get_uint8(tvb, offset+ci);
214
0
      if (v == 0xFE) {
215
0
        ci++;
216
0
        count = tvb_get_uint8(tvb, offset+ci);
217
0
        ci++;
218
0
        v = tvb_get_uint8(tvb, offset+ci);
219
0
        ci++;
220
0
        for (i=0;i < count && ui < 512;i++) {
221
0
          dmx_data[ui] = v;
222
0
          dmx_data_offset[ui] = ci-3;
223
0
          ui++;
224
0
        }
225
0
      } else if (v == 0xFD) {
226
0
        ci++;
227
0
        v = tvb_get_uint8(tvb, offset+ci);
228
0
        dmx_data[ui] = v;
229
0
        dmx_data_offset[ui] = ci;
230
0
        ci++;
231
0
        ui++;
232
0
      } else {
233
0
        dmx_data[ui] = v;
234
0
        dmx_data_offset[ui] = ci;
235
0
        ui++;
236
0
        ci++;
237
0
      }
238
0
    }
239
0
    dmx_data_offset[ui] = ci;
240
0
  } else {
241
0
    for (ui=0; ui < length;ui++) {
242
0
      dmx_data[ui] =  tvb_get_uint8(tvb, offset+ui);
243
0
      dmx_data_offset[ui] = ui;
244
0
    }
245
0
    dmx_data_offset[ui] = ui;
246
0
  }
247
248
249
0
  if ((type == ENTTEC_DATA_TYPE_DMX || type == ENTTEC_DATA_TYPE_RLE) && global_disp_col_count > 0) {
250
0
    hi = proto_tree_add_item(tree,
251
0
          hf_enttec_dmx_data_data,
252
0
          tvb,
253
0
          offset,
254
0
          length,
255
0
          ENC_NA);
256
257
0
    si = proto_item_add_subtree(hi, ett_enttec);
258
259
0
    row_count = (ui/global_disp_col_count) + ((ui%global_disp_col_count) == 0 ? 0 : 1);
260
0
    dmx_epstr = wmem_strbuf_create(pinfo->pool);
261
0
    for (r=0; r < row_count;r++) {
262
0
      for (c=0;(c < global_disp_col_count) && (((r*global_disp_col_count)+c) < ui);c++) {
263
0
        if ((global_disp_col_count > 1) && (c % (global_disp_col_count/2)) == 0) {
264
0
          wmem_strbuf_append_c(dmx_epstr, ' ');
265
0
        }
266
0
        v = dmx_data[(r*global_disp_col_count)+c];
267
0
        if (global_disp_chan_val_type == 0) {
268
0
          v = (v * 100) / 255;
269
0
          if (v == 100) {
270
0
            wmem_strbuf_append(dmx_epstr, "FL ");
271
0
          } else {
272
0
            wmem_strbuf_append_printf(dmx_epstr, chan_format[global_disp_chan_val_type], v);
273
0
          }
274
0
        } else {
275
0
          wmem_strbuf_append_printf(dmx_epstr, chan_format[global_disp_chan_val_type], v);
276
0
        }
277
0
      }
278
279
0
      start_offset = dmx_data_offset[(r*global_disp_col_count)];
280
0
      end_offset = dmx_data_offset[(r*global_disp_col_count)+c];
281
282
0
      proto_tree_add_none_format(si,hf_enttec_dmx_data_dmx_data, tvb,
283
0
            offset+start_offset,
284
0
            end_offset-start_offset,
285
0
            string_format[global_disp_chan_nr_type], (r*global_disp_col_count)+1,
286
0
            wmem_strbuf_get_str(dmx_epstr));
287
0
      wmem_strbuf_truncate(dmx_epstr, 0);
288
0
    }
289
290
0
    item = proto_tree_add_item(si, hf_enttec_dmx_data_data_filter, tvb,
291
0
        offset, length, ENC_NA );
292
0
    proto_item_set_hidden(item);
293
294
0
    offset += length;
295
0
  }
296
0
  else {
297
0
    proto_tree_add_item(tree, hf_enttec_dmx_data_data_filter, tvb,
298
0
          offset, length, ENC_NA);
299
0
    offset += length;
300
0
  }
301
302
303
304
0
  return offset;
305
0
}
306
307
static int
308
dissect_enttec_reset(tvbuff_t *tvb _U_, unsigned offset, proto_tree *tree _U_)
309
0
{
310
311
0
  return offset;
312
0
}
313
314
static int
315
dissect_enttec_udp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
316
0
{
317
0
  unsigned offset = 0;
318
0
  uint32_t head = 0;
319
0
  proto_tree *ti, *enttec_tree;
320
321
  /*
322
   * If not enough bytes for the header word, not an ENTTEC packet.
323
   */
324
0
  if (!tvb_bytes_exist(tvb, offset, 4))
325
0
    return 0;
326
327
0
  head = tvb_get_ntohl(tvb, offset);
328
0
  switch (head) {
329
330
0
  case ENTTEC_HEAD_ESPR:
331
0
  case ENTTEC_HEAD_ESPP:
332
0
  case ENTTEC_HEAD_ESAP:
333
0
  case ENTTEC_HEAD_ESDD:
334
0
  case ENTTEC_HEAD_ESZZ:
335
    /*
336
     * Valid packet type.
337
     */
338
0
    break;
339
340
0
  default:
341
    /*
342
     * Not a known DMX-over-UDP packet type, so probably not ENTTEC.
343
     */
344
0
    return 0;
345
0
  }
346
347
  /* Set the protocol column */
348
0
  col_set_str(pinfo->cinfo, COL_PROTOCOL, "ENTTEC");
349
350
  /* Clear out stuff in the info column */
351
0
  col_add_str(pinfo->cinfo, COL_INFO,
352
0
        val_to_str(pinfo->pool, head, enttec_head_vals, "Unknown (0x%08x)"));
353
354
0
  ti = proto_tree_add_item(tree, proto_enttec, tvb, offset, -1, ENC_NA);
355
0
  enttec_tree = proto_item_add_subtree(ti, ett_enttec);
356
357
0
  proto_tree_add_item(enttec_tree, hf_enttec_head, tvb,
358
0
      offset, 4, ENC_BIG_ENDIAN );
359
0
  offset += 4;
360
361
0
  switch (head) {
362
0
    case ENTTEC_HEAD_ESPR:
363
0
      offset = dissect_enttec_poll_reply( tvb, offset, enttec_tree);
364
0
      break;
365
366
0
    case ENTTEC_HEAD_ESPP:
367
0
      offset = dissect_enttec_poll( tvb, offset, enttec_tree);
368
0
      break;
369
370
0
    case ENTTEC_HEAD_ESAP:
371
0
      offset = dissect_enttec_ack( tvb, offset, enttec_tree);
372
0
      break;
373
374
0
    case ENTTEC_HEAD_ESDD:
375
0
      offset = dissect_enttec_dmx_data( tvb, pinfo, offset, enttec_tree);
376
0
      break;
377
378
0
    case ENTTEC_HEAD_ESZZ:
379
0
      offset = dissect_enttec_reset( tvb, offset, enttec_tree);
380
0
      break;
381
0
  }
382
383
0
  return offset;
384
0
}
385
386
static int
387
dissect_enttec_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
388
2
{
389
2
  unsigned offset = 0;
390
2
  uint32_t head = 0;
391
2
  proto_tree *ti,*enttec_tree;
392
393
  /*
394
   * If not enough bytes for the header word, don't try to
395
   * reassemble to get 4 bytes of header word, as we don't
396
   * know whether this will be an ENTTEC Config packet.
397
   */
398
2
  if (!tvb_bytes_exist(tvb, offset, 4))
399
1
    return 0;
400
401
1
  head = tvb_get_ntohl(tvb, offset);
402
1
  if (head != ENTTEC_HEAD_ESNC) {
403
    /*
404
     * Not a config packet, so probably not ENTTEC.
405
     */
406
1
    return 0;
407
1
  }
408
409
  /* XXX - reassemble to end of connection? */
410
411
  /* Set the protocol column */
412
0
  col_set_str(pinfo->cinfo, COL_PROTOCOL, "ENTTEC");
413
414
  /* Clear out stuff in the info column */
415
0
  col_add_str(pinfo->cinfo, COL_INFO,
416
0
        val_to_str(pinfo->pool, head, enttec_head_vals, "Unknown (0x%08x)"));
417
418
0
  ti = proto_tree_add_item(tree, proto_enttec, tvb, offset, -1, ENC_NA);
419
0
  enttec_tree = proto_item_add_subtree(ti, ett_enttec);
420
421
0
  proto_tree_add_item(enttec_tree, hf_enttec_head, tvb,
422
0
      offset, 4, ENC_BIG_ENDIAN );
423
  /* XXX - dissect the rest of the packet */
424
425
0
  return tvb_captured_length(tvb);
426
1
}
427
428
void
429
proto_register_enttec(void)
430
16
{
431
16
  static hf_register_info hf[] = {
432
    /* General */
433
16
    { &hf_enttec_head,
434
16
      { "Head", "enttec.head",
435
16
        FT_UINT32, BASE_HEX, VALS(enttec_head_vals), 0x0,
436
16
        NULL, HFILL } },
437
16
    { &hf_enttec_poll_reply_mac,
438
16
      { "MAC", "enttec.poll_reply.mac",
439
16
        FT_ETHER, BASE_NONE, NULL, 0x0,
440
16
        NULL, HFILL } },
441
16
    { &hf_enttec_poll_reply_node_type,
442
16
      { "Node Type", "enttec.poll_reply.node_type",
443
16
        FT_UINT16, BASE_HEX, NULL, 0x0,
444
16
        NULL, HFILL } },
445
16
    { &hf_enttec_poll_reply_version,
446
16
      { "Version", "enttec.poll_reply.version",
447
16
        FT_UINT8, BASE_DEC, NULL, 0x0,
448
16
        NULL, HFILL } },
449
16
    { &hf_enttec_poll_reply_switch,
450
16
      { "Switch settings", "enttec.poll_reply.switch_settings",
451
16
        FT_UINT8, BASE_HEX, NULL, 0x0,
452
16
        NULL, HFILL } },
453
16
    { &hf_enttec_poll_reply_name,
454
16
      { "Name", "enttec.poll_reply.name",
455
16
        FT_STRING, BASE_NONE, NULL, 0x0,
456
16
        NULL, HFILL } },
457
16
    { &hf_enttec_poll_reply_option,
458
16
      { "Option Field", "enttec.poll_reply.option_field",
459
16
        FT_UINT8, BASE_HEX, NULL, 0x0,
460
16
        NULL, HFILL } },
461
16
    { &hf_enttec_poll_reply_tos,
462
16
      { "TOS", "enttec.poll_reply.tos",
463
16
        FT_UINT8, BASE_HEX, NULL, 0x0,
464
16
        NULL, HFILL } },
465
16
    { &hf_enttec_poll_reply_ttl,
466
16
      { "TTL", "enttec.poll_reply.ttl",
467
16
        FT_UINT8, BASE_DEC, NULL, 0x0,
468
16
        NULL, HFILL } },
469
16
    { &hf_enttec_dmx_data_universe,
470
16
      { "Universe", "enttec.dmx_data.universe",
471
16
        FT_UINT8, BASE_DEC, NULL, 0x0,
472
16
        NULL, HFILL } },
473
16
    { &hf_enttec_dmx_data_start_code,
474
16
      { "Start Code", "enttec.dmx_data.start_code",
475
16
        FT_UINT8, BASE_DEC, NULL, 0x0,
476
16
        NULL, HFILL } },
477
16
    { &hf_enttec_dmx_data_type,
478
16
      { "Data Type", "enttec.dmx_data.type",
479
16
        FT_UINT8, BASE_HEX, VALS(enttec_data_type_vals), 0x0,
480
16
        NULL, HFILL } },
481
16
    { &hf_enttec_dmx_data_size,
482
16
      { "Data Size", "enttec.dmx_data.size",
483
16
        FT_UINT16, BASE_DEC, NULL, 0x0,
484
16
        NULL, HFILL } },
485
16
    { &hf_enttec_dmx_data_data,
486
16
      { "DMX Data", "enttec.dmx_data.data",
487
16
        FT_NONE, BASE_NONE, NULL, 0x0,
488
16
        NULL, HFILL } },
489
16
    { &hf_enttec_dmx_data_data_filter,
490
16
      { "DMX Data", "enttec.dmx_data.data_filter",
491
16
        FT_BYTES, BASE_NONE, NULL, 0x0,
492
16
        NULL, HFILL } },
493
16
    { &hf_enttec_dmx_data_dmx_data,
494
16
      { "DMX Data", "enttec.dmx_data.dmx_data",
495
16
        FT_NONE, BASE_NONE, NULL, 0x0,
496
16
        NULL, HFILL } },
497
16
    { &hf_enttec_poll_type,
498
16
      { "Reply Type", "enttec.poll.reply_type",
499
16
        FT_UINT8, BASE_DEC, NULL, 0x0,
500
16
        NULL, HFILL } }
501
16
  };
502
503
16
  static int *ett[] = {
504
16
    &ett_enttec,
505
16
  };
506
507
16
  module_t *enttec_module;
508
509
16
  static const enum_val_t disp_chan_val_types[] = {
510
16
    { "pro", "Percent", 0 },
511
16
    { "hex", "Hexadecimal", 1 },
512
16
    { "dec", "Decimal", 2 },
513
16
    { NULL, NULL, 0 }
514
16
  };
515
516
16
  static const enum_val_t disp_chan_nr_types[] = {
517
16
    { "hex", "Hexadecimal", 0 },
518
16
    { "dec", "Decimal", 1 },
519
16
    { NULL, NULL, 0 }
520
16
  };
521
522
16
  static const enum_val_t col_count[] = {
523
16
    { "6", "6", 6 },
524
16
    { "10", "10", 10 },
525
16
    { "12", "12", 12 },
526
16
    { "16", "16", 16 },
527
16
    { "24", "24", 24 },
528
16
    { NULL, NULL, 0 }
529
16
  };
530
531
16
  proto_enttec = proto_register_protocol("ENTTEC", "ENTTEC","enttec");
532
16
  proto_register_field_array(proto_enttec,hf,array_length(hf));
533
16
  proto_register_subtree_array(ett,array_length(ett));
534
535
16
  enttec_udp_handle = register_dissector("enttec.udp", dissect_enttec_udp,proto_enttec);
536
16
  enttec_tcp_handle = register_dissector("enttec.tcp", dissect_enttec_tcp,proto_enttec);
537
538
16
  enttec_module = prefs_register_protocol(proto_enttec, NULL);
539
540
16
  prefs_register_enum_preference(enttec_module, "dmx_disp_chan_val_type",
541
16
        "DMX Display channel value type",
542
16
        "The way DMX values are displayed",
543
16
        &global_disp_chan_val_type,
544
16
        disp_chan_val_types, false);
545
546
16
  prefs_register_enum_preference(enttec_module, "dmx_disp_chan_nr_type",
547
16
        "DMX Display channel nr. type",
548
16
        "The way DMX channel numbers are displayed",
549
16
        &global_disp_chan_nr_type,
550
16
        disp_chan_nr_types, false);
551
552
16
  prefs_register_enum_preference(enttec_module, "dmx_disp_col_count",
553
16
        "DMX Display Column Count",
554
16
        "The number of columns for the DMX display",
555
16
        &global_disp_col_count,
556
16
        col_count, false);
557
16
}
558
559
/* The registration hand-off routing */
560
void
561
16
proto_reg_handoff_enttec(void) {
562
16
  dissector_add_uint_with_preference("tcp.port",TCP_PORT_ENTTEC,enttec_tcp_handle);
563
16
  dissector_add_uint_with_preference("udp.port",UDP_PORT_ENTTEC,enttec_udp_handle);
564
16
}
565
566
/*
567
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
568
 *
569
 * Local variables:
570
 * c-basic-offset: 8
571
 * tab-width: 8
572
 * indent-tabs-mode: t
573
 * End:
574
 *
575
 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
576
 * :indentSize=8:tabSize=8:noTabs=false:
577
 */