Bug Summary

File:builds/wireshark/wireshark/epan/dfilter/syntax-tree.c
Warning:line 103, column 14
Value stored to 's' during its initialization is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name syntax-tree.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -fno-delete-null-pointer-checks -mframe-pointer=all -relaxed-aliasing -fmath-errno -ffp-contract=on -fno-rounding-math -ffloat16-excess-precision=fast -fbfloat16-excess-precision=fast -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/builds/wireshark/wireshark/build -fcoverage-compilation-dir=/builds/wireshark/wireshark/build -resource-dir /usr/lib/llvm-21/lib/clang/21 -isystem /usr/include/glib-2.0 -isystem /usr/lib/x86_64-linux-gnu/glib-2.0/include -D G_DISABLE_DEPRECATED -D G_DISABLE_SINGLE_INCLUDES -D WS_BUILD_DLL -D WS_DEBUG -D WS_DEBUG_UTF_8 -I /builds/wireshark/wireshark/build -I /builds/wireshark/wireshark -I /builds/wireshark/wireshark/include -I /builds/wireshark/wireshark/epan/dfilter -I /builds/wireshark/wireshark/build/epan/dfilter -I /builds/wireshark/wireshark/epan -I /builds/wireshark/wireshark/tools/lemon -D _GLIBCXX_ASSERTIONS -internal-isystem /usr/lib/llvm-21/lib/clang/21/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -fmacro-prefix-map=/builds/wireshark/wireshark/= -fmacro-prefix-map=/builds/wireshark/wireshark/build/= -fmacro-prefix-map=../= -Wno-format-nonliteral -std=gnu11 -ferror-limit 19 -fvisibility=hidden -fwrapv -fwrapv-pointer -fstrict-flex-arrays=3 -stack-protector 2 -fstack-clash-protection -fcf-protection=full -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -fexceptions -fcolor-diagnostics -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /builds/wireshark/wireshark/sbout/2026-03-15-100342-3641-1 -x c /builds/wireshark/wireshark/epan/dfilter/syntax-tree.c
1/*
2 * Wireshark - Network traffic analyzer
3 * By Gerald Combs <[email protected]>
4 * Copyright 2001 Gerald Combs
5 *
6 * SPDX-License-Identifier: GPL-2.0-or-later
7 */
8
9#include "config.h"
10#define WS_LOG_DOMAIN"DFilter" LOG_DOMAIN_DFILTER"DFilter"
11
12#include "syntax-tree.h"
13#include <wsutil/wmem/wmem.h>
14#include <wsutil/str_util.h>
15#include <wsutil/glib-compat.h>
16#include "sttype-op.h"
17#include "sttype-function.h"
18#include "dfilter-int.h"
19
20/* Keep track of sttype_t's via their sttype_id_t number */
21static sttype_t* type_list[STTYPE_NUM_TYPES];
22
23
24void
25sttype_init(void)
26{
27 sttype_register_field();
28 sttype_register_function();
29 sttype_register_number();
30 sttype_register_pointer();
31 sttype_register_set();
32 sttype_register_slice();
33 sttype_register_string();
34 sttype_register_opers();
35}
36
37void
38sttype_cleanup(void)
39{
40 /* nothing to do */
41}
42
43
44void
45sttype_register(sttype_t *type)
46{
47 sttype_id_t type_id;
48
49 type_id = type->id;
50
51 /* Check input */
52 ws_assert(type_id < STTYPE_NUM_TYPES)do { if ((1) && !(type_id < STTYPE_NUM_TYPES)) ws_log_fatal_full
("DFilter", LOG_LEVEL_ERROR, "epan/dfilter/syntax-tree.c", 52
, __func__, "assertion failed: %s", "type_id < STTYPE_NUM_TYPES"
); } while (0)
;
53
54 /* Don't re-register. */
55 ws_assert(type_list[type_id] == NULL)do { if ((1) && !(type_list[type_id] == ((void*)0))) ws_log_fatal_full
("DFilter", LOG_LEVEL_ERROR, "epan/dfilter/syntax-tree.c", 55
, __func__, "assertion failed: %s", "type_list[type_id] == ((void*)0)"
); } while (0)
;
56
57 type_list[type_id] = type;
58}
59
60static sttype_t*
61sttype_lookup(sttype_id_t type_id)
62{
63 sttype_t *result;
64
65 /* Check input */
66 ws_assert(type_id < STTYPE_NUM_TYPES)do { if ((1) && !(type_id < STTYPE_NUM_TYPES)) ws_log_fatal_full
("DFilter", LOG_LEVEL_ERROR, "epan/dfilter/syntax-tree.c", 66
, __func__, "assertion failed: %s", "type_id < STTYPE_NUM_TYPES"
); } while (0)
;
67
68 result = type_list[type_id];
69
70 /* Check output. */
71 ws_assert(result != NULL)do { if ((1) && !(result != ((void*)0))) ws_log_fatal_full
("DFilter", LOG_LEVEL_ERROR, "epan/dfilter/syntax-tree.c", 71
, __func__, "assertion failed: %s", "result != ((void*)0)"); }
while (0)
;
72
73 return result;
74}
75
76const char *
77sttype_name(const sttype_id_t type)
78{
79 switch (type) {
80 case STTYPE_UNINITIALIZED: return "UNINITIALIZED";
81 case STTYPE_TEST: return "TEST";
82 case STTYPE_LITERAL: return "LITERAL";
83 case STTYPE_UNPARSED: return "UNPARSED";
84 case STTYPE_REFERENCE: return "REFERENCE";
85 case STTYPE_STRING: return "STRING";
86 case STTYPE_CHARCONST: return "CHARCONST";
87 case STTYPE_NUMBER: return "NUMBER";
88 case STTYPE_FIELD: return "FIELD";
89 case STTYPE_FVALUE: return "FVALUE";
90 case STTYPE_SLICE: return "SLICE";
91 case STTYPE_FUNCTION: return "FUNCTION";
92 case STTYPE_SET: return "SET";
93 case STTYPE_PCRE: return "PCRE";
94 case STTYPE_ARITHMETIC: return "ARITHMETIC";
95 case STTYPE_NUM_TYPES: return "NUM_TYPES";
96 }
97 return "(unknown sttype)";
98}
99
100const char *
101stnode_op_name(const stnode_op_t op)
102{
103 const char *s = "(null)";
Value stored to 's' during its initialization is never read
104
105 switch(op) {
106 case STNODE_OP_NOT:
107 s = "TEST_NOT";
108 break;
109 case STNODE_OP_AND:
110 s = "TEST_AND";
111 break;
112 case STNODE_OP_OR:
113 s = "TEST_OR";
114 break;
115 case STNODE_OP_ALL_EQ:
116 s = "TEST_ALL_EQ";
117 break;
118 case STNODE_OP_ANY_EQ:
119 s = "TEST_ANY_EQ";
120 break;
121 case STNODE_OP_ALL_NE:
122 s = "TEST_ALL_NE";
123 break;
124 case STNODE_OP_ANY_NE:
125 s = "TEST_ANY_NE";
126 break;
127 case STNODE_OP_GT:
128 s = "TEST_GT";
129 break;
130 case STNODE_OP_GE:
131 s = "TEST_GE";
132 break;
133 case STNODE_OP_LT:
134 s = "TEST_LT";
135 break;
136 case STNODE_OP_LE:
137 s = "TEST_LE";
138 break;
139 case STNODE_OP_BITWISE_AND:
140 s = "OP_BITWISE_AND";
141 break;
142 case STNODE_OP_UNARY_MINUS:
143 s = "OP_UNARY_MINUS";
144 break;
145 case STNODE_OP_ADD:
146 s = "OP_ADD";
147 break;
148 case STNODE_OP_SUBTRACT:
149 s = "OP_SUBTRACT";
150 break;
151 case STNODE_OP_MULTIPLY:
152 s = "OP_MULTIPLY";
153 break;
154 case STNODE_OP_DIVIDE:
155 s = "OP_DIVIDE";
156 break;
157 case STNODE_OP_MODULO:
158 s = "OP_MODULO";
159 break;
160 case STNODE_OP_CONTAINS:
161 s = "TEST_CONTAINS";
162 break;
163 case STNODE_OP_MATCHES:
164 s = "TEST_MATCHES";
165 break;
166 case STNODE_OP_IN:
167 s = "TEST_IN";
168 break;
169 case STNODE_OP_NOT_IN:
170 s = "TEST_NOT_IN";
171 break;
172 case STNODE_OP_UNINITIALIZED:
173 s = "(uninitialized)";
174 break;
175 }
176
177 return s;
178}
179
180void
181stnode_clear(stnode_t *node)
182{
183 if (node->type) {
184 if (node->type->func_free && node->data) {
185 node->type->func_free(node->data);
186 }
187 }
188 else {
189 ws_assert(!node->data)do { if ((1) && !(!node->data)) ws_log_fatal_full(
"DFilter", LOG_LEVEL_ERROR, "epan/dfilter/syntax-tree.c", 189
, __func__, "assertion failed: %s", "!node->data"); } while
(0)
;
190 }
191
192 node->type = NULL((void*)0);
193 node->data = NULL((void*)0);
194 g_free(node->repr_display);
195 node->repr_display = NULL((void*)0);
196 g_free(node->repr_debug);
197 node->repr_debug = NULL((void*)0);
198 g_free(node->repr_token);
199 node->repr_token = NULL((void*)0);
200 node->location.col_start = -1;
201 node->location.col_len = 0;
202 node->flags = 0;
203}
204
205void
206stnode_init(stnode_t *node, sttype_id_t type_id, void *data, char *token, df_loc_t loc)
207{
208 sttype_t *type;
209
210 ws_assert(!node->type)do { if ((1) && !(!node->type)) ws_log_fatal_full(
"DFilter", LOG_LEVEL_ERROR, "epan/dfilter/syntax-tree.c", 210
, __func__, "assertion failed: %s", "!node->type"); } while
(0)
;
211 ws_assert(!node->data)do { if ((1) && !(!node->data)) ws_log_fatal_full(
"DFilter", LOG_LEVEL_ERROR, "epan/dfilter/syntax-tree.c", 211
, __func__, "assertion failed: %s", "!node->data"); } while
(0)
;
212 node->repr_display = NULL((void*)0);
213 node->repr_debug = NULL((void*)0);
214 node->repr_token = token;
215 node->location = loc;
216 node->flags = 0;
217
218 if (type_id == STTYPE_UNINITIALIZED) {
219 node->type = NULL((void*)0);
220 node->data = NULL((void*)0);
221 }
222 else {
223 /* Creating an initialized node with a NULL pointer is
224 * allowed and needs to be safe. The parser relies on that. */
225 type = sttype_lookup(type_id);
226 ws_assert(type)do { if ((1) && !(type)) ws_log_fatal_full("DFilter",
LOG_LEVEL_ERROR, "epan/dfilter/syntax-tree.c", 226, __func__
, "assertion failed: %s", "type"); } while (0)
;
227 node->type = type;
228 if (type->func_new) {
229 node->data = type->func_new(data);
230 }
231 else {
232 node->data = data;
233 }
234 }
235}
236
237void
238stnode_replace(stnode_t *node, sttype_id_t type_id, void *data)
239{
240 char *token = g_strdup(node->repr_token)g_strdup_inline (node->repr_token);
241 df_loc_t loc = node->location;
242 uint16_t flags = node->flags;
243 stnode_clear(node);
244 stnode_init(node, type_id, data, token, loc);
245 node->flags = flags;
246}
247
248void
249stnode_mutate(stnode_t *node, sttype_id_t type_id)
250{
251 //FIXME: Assert there all the same sttype
252 node->type = sttype_lookup(type_id);
253 ws_assert(node->type)do { if ((1) && !(node->type)) ws_log_fatal_full("DFilter"
, LOG_LEVEL_ERROR, "epan/dfilter/syntax-tree.c", 253, __func__
, "assertion failed: %s", "node->type"); } while (0)
;
254}
255
256stnode_t*
257stnode_new(sttype_id_t type_id, void *data, char *token, df_loc_t loc)
258{
259 stnode_t *node = g_new0(stnode_t, 1)((stnode_t *) g_malloc0_n ((1), sizeof (stnode_t)));
260 stnode_init(node, type_id, data, token, loc);
261 return node;
262}
263
264stnode_t*
265stnode_new_empty(sttype_id_t type_id)
266{
267 df_loc_t loc = {-1, 0};
268 return stnode_new(type_id, NULL((void*)0), NULL((void*)0), loc);
269}
270
271stnode_t*
272stnode_dup(const stnode_t *node)
273{
274 stnode_t *new;
275
276 new = g_new(stnode_t, 1)((stnode_t *) g_malloc_n ((1), sizeof (stnode_t)));
277 new->repr_display = NULL((void*)0);
278 new->repr_debug = NULL((void*)0);
279 new->repr_token = g_strdup(node->repr_token)g_strdup_inline (node->repr_token);
280 new->location = node->location;
281 new->flags = node->flags;
282
283 new->type = node->type;
284 if (node->type == NULL((void*)0))
285 new->data = NULL((void*)0);
286 else if (node->type->func_dup)
287 new->data = node->type->func_dup(node->data);
288 else
289 new->data = node->data;
290
291 return new;
292}
293
294void
295stnode_free(stnode_t *node)
296{
297 stnode_clear(node);
298 g_free(node);
299}
300
301const char*
302stnode_type_name(const stnode_t *node)
303{
304 return sttype_name(node->type->id);
305}
306
307sttype_id_t
308stnode_type_id(const stnode_t *node)
309{
310 if (node->type)
311 return node->type->id;
312 else
313 return STTYPE_UNINITIALIZED;
314}
315
316void *
317stnode_data(stnode_t *node)
318{
319 return node->data;
320}
321
322GString *
323stnode_string(stnode_t *node)
324{
325 ws_assert(stnode_type_id(node) == STTYPE_STRING)do { if ((1) && !(stnode_type_id(node) == STTYPE_STRING
)) ws_log_fatal_full("DFilter", LOG_LEVEL_ERROR, "epan/dfilter/syntax-tree.c"
, 325, __func__, "assertion failed: %s", "stnode_type_id(node) == STTYPE_STRING"
); } while (0)
;
326 return stnode_data(node);
327}
328
329void *
330stnode_steal_data(stnode_t *node)
331{
332 void *data = node->data;
333 ws_assert(data)do { if ((1) && !(data)) ws_log_fatal_full("DFilter",
LOG_LEVEL_ERROR, "epan/dfilter/syntax-tree.c", 333, __func__
, "assertion failed: %s", "data"); } while (0)
;
334 node->data = NULL((void*)0);
335 return data;
336}
337
338const char *
339stnode_token(const stnode_t *node)
340{
341 return node->repr_token;
342}
343
344df_loc_t
345stnode_location(const stnode_t *node)
346{
347 return node->location;
348}
349
350void
351stnode_set_location(stnode_t *node, df_loc_t loc)
352{
353 node->location = loc;
354}
355
356bool_Bool
357stnode_get_flags(stnode_t *node, uint16_t flags)
358{
359 return node->flags & flags;
360}
361
362void
363stnode_set_flags(stnode_t *node, uint16_t flags)
364{
365 node->flags |= flags;
366}
367
368/* Finds the first and last location from a set and creates
369 * a new location from start of first (col_start) to end of
370 * last (col_start + col_len). Sets the result to dst. */
371void
372stnode_merge_location(stnode_t *dst, stnode_t *n1, stnode_t *n2)
373{
374 df_loc_t first, last;
375 df_loc_t loc2;
376
377 first = last = stnode_location(n1);
378 loc2 = stnode_location(n2);
379 if (loc2.col_start >= 0 && loc2.col_start > first.col_start)
380 last = loc2;
381 dst->location.col_start = first.col_start;
382 dst->location.col_len = last.col_start - first.col_start + last.col_len;
383}
384
385#define IS_OPERATOR(node)(stnode_type_id(node) == STTYPE_TEST || stnode_type_id(node) ==
STTYPE_ARITHMETIC)
\
386 (stnode_type_id(node) == STTYPE_TEST || \
387 stnode_type_id(node) == STTYPE_ARITHMETIC)
388
389static char *
390_node_tostr(stnode_t *node, bool_Bool pretty)
391{
392 char *s, *repr;
393
394 if (node->type->func_tostr == NULL((void*)0))
395 s = g_strdup("FIXME")g_strdup_inline ("FIXME");
396 else
397 s = node->type->func_tostr(node->data, pretty);
398
399 if (pretty)
400 return s;
401
402 if (IS_OPERATOR(node)(stnode_type_id(node) == STTYPE_TEST || stnode_type_id(node) ==
STTYPE_ARITHMETIC)
) {
403 repr = s;
404 }
405 else {
406 repr = ws_strdup_printf("%s(%s)", stnode_type_name(node), s)wmem_strdup_printf(((void*)0), "%s(%s)", stnode_type_name(node
), s)
;
407 g_free(s);
408 }
409
410 return repr;
411}
412
413const char *
414stnode_tostr(stnode_t *node, bool_Bool pretty)
415{
416 if (pretty && IS_OPERATOR(node)(stnode_type_id(node) == STTYPE_TEST || stnode_type_id(node) ==
STTYPE_ARITHMETIC)
&& node->repr_token != NULL((void*)0)) {
417 /* Some operators can have synonyms, like "or" and "||".
418 * Show the user the same representation as he typed. */
419 g_free(node->repr_display);
420 node->repr_display = g_strdup(node->repr_token)g_strdup_inline (node->repr_token);
421 return node->repr_display;
422 }
423
424 char *str = _node_tostr(node, pretty);
425
426 if (pretty) {
427 g_free(node->repr_display);
428 node->repr_display = str;
429 }
430 else {
431 g_free(node->repr_debug);
432 node->repr_debug = str;
433 }
434
435 return str;
436}
437
438static char *
439sprint_node(stnode_t *node)
440{
441 wmem_strbuf_t *buf = wmem_strbuf_new(NULL((void*)0), NULL((void*)0));
442
443 wmem_strbuf_append_printf(buf, "{ ");
444 wmem_strbuf_append_printf(buf, "type = %s, ", stnode_type_name(node));
445 wmem_strbuf_append_printf(buf, "data = %s, ", stnode_todebug(node)stnode_tostr(node, 0));
446 wmem_strbuf_append_printf(buf, "location = %ld:%zu",
447 node->location.col_start, node->location.col_len);
448 wmem_strbuf_append_printf(buf, " }");
449 return wmem_strbuf_finalize(buf);
450}
451
452void
453log_node_full(enum ws_log_level level,
454 const char *file, int line, const char *func,
455 stnode_t *node, const char *msg)
456{
457 if (!ws_log_msg_is_active(WS_LOG_DOMAIN"DFilter", level))
458 return;
459
460 if (node == NULL((void*)0)) {
461 ws_log_write_always_full(WS_LOG_DOMAIN"DFilter", level,
462 file, line, func, "%s is NULL", msg);
463 return;
464 }
465
466 char *str = sprint_node(node);
467
468 ws_log_write_always_full(WS_LOG_DOMAIN"DFilter", level, file, line, func,
469 "%s = %s", msg, str);
470
471 g_free(str);
472}
473
474void
475log_test_full(enum ws_log_level level,
476 const char *file, int line, const char *func,
477 stnode_t *node, const char *msg)
478{
479 if (!ws_log_msg_is_active(WS_LOG_DOMAIN"DFilter", level))
480 return;
481
482 if (node == NULL((void*)0)) {
483 ws_log_write_always_full(WS_LOG_DOMAIN"DFilter", level,
484 file, line, func, "%s is NULL", msg);
485 return;
486 }
487
488 stnode_op_t st_op;
489 stnode_t *st_lhs = NULL((void*)0), *st_rhs = NULL((void*)0);
490 char *lhs = NULL((void*)0), *rhs = NULL((void*)0);
491
492 sttype_oper_get(node, &st_op, &st_lhs, &st_rhs);
493
494 if (st_lhs)
495 lhs = sprint_node(st_lhs);
496 if (st_rhs)
497 rhs = sprint_node(st_rhs);
498
499 ws_log_write_always_full(WS_LOG_DOMAIN"DFilter", level, file, line, func,
500 "%s:\n LHS = %s\n RHS = %s",
501 stnode_todebug(node)stnode_tostr(node, 0),
502 lhs ? lhs : "NULL",
503 rhs ? rhs : "NULL");
504
505 g_free(lhs);
506 g_free(rhs);
507}
508
509static void
510indent(wmem_strbuf_t *buf, int level)
511{
512 for (int i = 0; i < level * 2; i++) {
513 wmem_strbuf_append_c(buf, ' ');
514 }
515 wmem_strbuf_append_printf(buf, "% 2d ", level);
516}
517
518static void
519visit_tree(wmem_strbuf_t *buf, stnode_t *node, int level)
520{
521 stnode_t *left, *right;
522 stnode_t *lower, *upper;
523 GSList *params;
524 GSList *nodelist;
525
526 if (stnode_type_id(node) == STTYPE_TEST ||
527 stnode_type_id(node) == STTYPE_ARITHMETIC) {
528 wmem_strbuf_append_printf(buf, "%s:\n", stnode_todebug(node)stnode_tostr(node, 0));
529 sttype_oper_get(node, NULL((void*)0), &left, &right);
530 if (left && right) {
531 indent(buf, level + 1);
532 visit_tree(buf, left, level + 1);
533 wmem_strbuf_append_c(buf, '\n');
534 indent(buf, level + 1);
535 visit_tree(buf, right, level + 1);
536 }
537 else if (left) {
538 indent(buf, level + 1);
539 visit_tree(buf, left, level + 1);
540 }
541 else if (right) {
542 ws_assert_not_reached()ws_log_fatal_full("DFilter", LOG_LEVEL_ERROR, "epan/dfilter/syntax-tree.c"
, 542, __func__, "assertion \"not reached\" failed")
;
543 }
544 }
545 else if (stnode_type_id(node) == STTYPE_SET) {
546 nodelist = stnode_data(node);
547 wmem_strbuf_append_printf(buf, "SET(#%u):\n", g_slist_length(nodelist) / 2);
548 while (nodelist) {
549 indent(buf, level + 1);
550 lower = nodelist->data;
551 wmem_strbuf_append(buf, stnode_tostr(lower, false0));
552 /* Set elements are always in pairs; upper may be null. */
553 nodelist = g_slist_next(nodelist)((nodelist) ? (((GSList *)(nodelist))->next) : ((void*)0));
554 ws_assert(nodelist)do { if ((1) && !(nodelist)) ws_log_fatal_full("DFilter"
, LOG_LEVEL_ERROR, "epan/dfilter/syntax-tree.c", 554, __func__
, "assertion failed: %s", "nodelist"); } while (0)
;
555 upper = nodelist->data;
556 if (upper != NULL((void*)0)) {
557 wmem_strbuf_append(buf, " .. ");
558 wmem_strbuf_append(buf, stnode_tostr(upper, false0));
559 }
560 nodelist = g_slist_next(nodelist)((nodelist) ? (((GSList *)(nodelist))->next) : ((void*)0));
561 if (nodelist != NULL((void*)0)) {
562 wmem_strbuf_append_c(buf, '\n');
563 }
564 }
565 }
566 else if (stnode_type_id(node) == STTYPE_FUNCTION) {
567 wmem_strbuf_append_printf(buf, "%s:\n", stnode_todebug(node)stnode_tostr(node, 0));
568 params = sttype_function_params(node);
569 while (params) {
570 indent(buf, level + 1);
571 visit_tree(buf, params->data, level + 1);
572 if (params->next != NULL((void*)0)) {
573 wmem_strbuf_append_c(buf, '\n');
574 }
575 params = params->next;
576 }
577 }
578 else {
579 wmem_strbuf_append(buf, stnode_todebug(node)stnode_tostr(node, 0));
580 }
581}
582
583char *
584dump_syntax_tree_str(stnode_t *root)
585{
586 wmem_strbuf_t *buf = wmem_strbuf_new(NULL((void*)0), NULL((void*)0));
587 indent(buf, 0);
588 visit_tree(buf, root, 0);
589 return wmem_strbuf_finalize(buf);
590}
591
592void
593log_syntax_tree(enum ws_log_level level, stnode_t *root, const char *msg, char **cache_ptr)
594{
595 if (!ws_log_msg_is_active(LOG_DOMAIN_DFILTER"DFilter", level))
596 return;
597
598 char *str = dump_syntax_tree_str(root);
599
600 ws_log_write_always_full(LOG_DOMAIN_DFILTER"DFilter", level, NULL((void*)0), -1, NULL((void*)0),
601 "%s:\n%s", msg, str);
602
603 if (cache_ptr) {
604 *cache_ptr = str;
605 }
606 else {
607 g_free(str);
608 }
609}
610
611/*
612 * Editor modelines - https://www.wireshark.org/tools/modelines.html
613 *
614 * Local variables:
615 * c-basic-offset: 8
616 * tab-width: 8
617 * indent-tabs-mode: t
618 * End:
619 *
620 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
621 * :indentSize=8:tabSize=8:noTabs=false:
622 */