2 * Wireshark - Network traffic analyzer
3 * By Gerald Combs <gerald@wireshark.org>
4 * Copyright 2001 Gerald Combs
6 * SPDX-License-Identifier: GPL-2.0-or-later
10 #define WS_LOG_DOMAIN LOG_DOMAIN_DFILTER
15 #include "dfilter-int.h"
16 #include "syntax-tree.h"
20 #include <epan/epan_dissect.h>
21 #include <epan/exceptions.h>
23 #include "dfunctions.h"
24 #include "dfilter-macro.h"
25 #include "dfilter-plugin.h"
26 #include "scanner_lex.h"
27 #include <wsutil/wslog.h>
28 #include <wsutil/ws_assert.h>
32 #define DFILTER_TOKEN_ID_OFFSET 1
34 /* Holds the singular instance of our Lemon parser object */
35 static void* ParserObj
;
37 df_loc_t loc_empty
= {-1, 0};
40 dfilter_vfail(void *state
, int code
, df_loc_t loc
,
41 const char *format
, va_list args
)
43 df_error_t
**ptr
= &((dfstate_t
*)state
)->error
;
44 /* If we've already reported one error, don't overwite it */
48 *ptr
= df_error_new_vprintf(code
, &loc
, format
, args
);
52 dfilter_fail(void *state
, int code
, df_loc_t loc
,
53 const char *format
, ...)
57 va_start(args
, format
);
58 dfilter_vfail(state
, code
, loc
, format
, args
);
63 dfilter_fail_throw(void *state
, int code
, df_loc_t loc
, const char *format
, ...)
67 va_start(args
, format
);
68 dfilter_vfail(state
, code
, loc
, format
, args
);
74 dfw_set_error_location(dfwork_t
*dfw
, df_loc_t loc
)
76 ws_assert(dfw
->error
);
77 dfw
->error
->loc
= loc
;
81 dfilter_resolve_unparsed(const char *name
, GPtrArray
*deprecated
)
83 header_field_info
*hfinfo
;
85 hfinfo
= proto_registrar_get_byname(name
);
87 /* It's a field name */
91 hfinfo
= proto_registrar_get_byalias(name
);
93 /* It's an aliased field name */
95 add_deprecated_token(deprecated
, name
);
99 /* It's not a field. */
103 /* Initialize the dfilter module */
108 ws_message("I expected ParserObj to be NULL\n");
109 /* Free the Lemon Parser object */
110 DfilterFree(ParserObj
, g_free
);
112 /* Allocate an instance of our Lemon-based parser */
113 ParserObj
= DfilterAlloc(g_malloc
);
115 /* Initialize the syntax-tree sub-sub-system */
119 dfilter_macro_init();
120 dfilter_plugins_init();
123 /* Clean-up the dfilter module */
125 dfilter_cleanup(void)
127 dfilter_plugins_cleanup();
128 dfilter_macro_cleanup();
131 /* Free the Lemon Parser object */
133 DfilterFree(ParserObj
, g_free
);
136 /* Clean up the syntax-tree sub-sub-system */
141 dfilter_new(GPtrArray
*deprecated
)
145 df
= g_new0(dfilter_t
, 1);
147 df
->function_stack
= NULL
;
148 df
->set_stack
= NULL
;
151 df
->deprecated
= g_ptr_array_ref(deprecated
);
155 /* Given a GPtrArray of instructions (dfvm_insn_t),
158 free_insns(GPtrArray
*insns
)
163 for (i
= 0; i
< insns
->len
; i
++) {
164 insn
= (dfvm_insn_t
*)g_ptr_array_index(insns
, i
);
165 dfvm_insn_free(insn
);
167 g_ptr_array_free(insns
, true);
171 dfilter_free(dfilter_t
*df
)
177 free_insns(df
->insns
);
180 g_free(df
->interesting_fields
);
182 g_hash_table_destroy(df
->references
);
183 g_hash_table_destroy(df
->raw_references
);
186 g_ptr_array_unref(df
->deprecated
);
188 if (df
->function_stack
!= NULL
) {
189 ws_critical("Function stack list should be NULL");
190 g_slist_free(df
->function_stack
);
193 if (df
->set_stack
!= NULL
) {
194 ws_critical("Set stack list should be NULL");
195 g_slist_free(df
->set_stack
);
199 g_slist_free_full(df
->warnings
, g_free
);
201 g_free(df
->registers
);
202 g_free(df
->expanded_text
);
203 g_free(df
->syntax_tree_str
);
207 static void free_refs_array(void *data
)
209 /* Array data must be freed. */
210 (void)g_ptr_array_free(data
, true);
214 dfsyntax_new(unsigned flags
)
216 dfsyntax_t
*dfs
= g_new0(dfsyntax_t
, 1);
217 dfs
->deprecated
= g_ptr_array_new_full(0, g_free
);
223 dfsyntax_free(dfsyntax_t
*dfs
)
226 df_error_free(&dfs
->error
);
229 stnode_free(dfs
->st_root
);
232 g_ptr_array_unref(dfs
->deprecated
);
235 stnode_free(dfs
->lval
);
237 if (dfs
->quoted_string
)
238 g_string_free(dfs
->quoted_string
, TRUE
);
246 dfwork_new(const char *expanded_text
, unsigned flags
)
248 dfwork_t
*dfw
= g_new0(dfwork_t
, 1);
249 dfw
->expanded_text
= g_strdup(expanded_text
);
253 g_hash_table_new_full(g_direct_hash
, g_direct_equal
,
254 NULL
, (GDestroyNotify
)free_refs_array
);
256 dfw
->raw_references
=
257 g_hash_table_new_full(g_direct_hash
, g_direct_equal
,
258 NULL
, (GDestroyNotify
)free_refs_array
);
260 dfw
->dfw_scope
= wmem_allocator_new(WMEM_ALLOCATOR_SIMPLE
);
266 dfwork_free(dfwork_t
*dfw
)
269 stnode_free(dfw
->st_root
);
272 if (dfw
->loaded_fields
) {
273 g_hash_table_destroy(dfw
->loaded_fields
);
276 if (dfw
->loaded_raw_fields
) {
277 g_hash_table_destroy(dfw
->loaded_raw_fields
);
280 if (dfw
->interesting_fields
) {
281 g_hash_table_destroy(dfw
->interesting_fields
);
284 if (dfw
->references
) {
285 g_hash_table_destroy(dfw
->references
);
288 if (dfw
->raw_references
) {
289 g_hash_table_destroy(dfw
->raw_references
);
293 free_insns(dfw
->insns
);
297 g_ptr_array_unref(dfw
->deprecated
);
300 g_slist_free_full(dfw
->warnings
, g_free
);
302 g_free(dfw
->expanded_text
);
305 df_error_free(&dfw
->error
);
307 wmem_destroy_allocator(dfw
->dfw_scope
);
310 * We don't free the error message string; our caller will return
316 const char *tokenstr(int token
)
319 case TOKEN_TEST_AND
: return "TEST_AND";
320 case TOKEN_TEST_OR
: return "TEST_OR";
321 case TOKEN_TEST_XOR
: return "TEST_XOR";
322 case TOKEN_TEST_ALL_EQ
: return "TEST_ALL_EQ";
323 case TOKEN_TEST_ANY_EQ
: return "TEST_ANY_EQ";
324 case TOKEN_TEST_ALL_NE
: return "TEST_ALL_NE";
325 case TOKEN_TEST_ANY_NE
: return "TEST_ANY_NE";
326 case TOKEN_TEST_LT
: return "TEST_LT";
327 case TOKEN_TEST_LE
: return "TEST_LE";
328 case TOKEN_TEST_GT
: return "TEST_GT";
329 case TOKEN_TEST_GE
: return "TEST_GE";
330 case TOKEN_TEST_CONTAINS
: return "TEST_CONTAINS";
331 case TOKEN_TEST_MATCHES
: return "TEST_MATCHES";
332 case TOKEN_BITWISE_AND
: return "BITWISE_AND";
333 case TOKEN_PLUS
: return "PLUS";
334 case TOKEN_MINUS
: return "MINUS";
335 case TOKEN_STAR
: return "STAR";
336 case TOKEN_RSLASH
: return "RSLASH";
337 case TOKEN_PERCENT
: return "PERCENT";
338 case TOKEN_TEST_NOT
: return "TEST_NOT";
339 case TOKEN_STRING
: return "STRING";
340 case TOKEN_CHARCONST
: return "CHARCONST";
341 case TOKEN_IDENTIFIER
: return "IDENTIFIER";
342 case TOKEN_UNPARSED
: return "UNPARSED";
343 case TOKEN_LITERAL
: return "LITERAL";
344 case TOKEN_NUMBER
: return "NUMBER";
345 case TOKEN_FIELD
: return "FIELD";
346 case TOKEN_LBRACKET
: return "LBRACKET";
347 case TOKEN_RBRACKET
: return "RBRACKET";
348 case TOKEN_COMMA
: return "COMMA";
349 case TOKEN_RANGE_NODE
: return "RANGE_NODE";
350 case TOKEN_TEST_IN
: return "TEST_IN";
351 case TOKEN_LBRACE
: return "LBRACE";
352 case TOKEN_RBRACE
: return "RBRACE";
353 case TOKEN_DOTDOT
: return "DOTDOT";
354 case TOKEN_LPAREN
: return "LPAREN";
355 case TOKEN_RPAREN
: return "RPAREN";
356 case TOKEN_DOLLAR
: return "DOLLAR";
357 case TOKEN_ATSIGN
: return "ATSIGN";
358 case TOKEN_HASH
: return "HASH";
359 case TOKEN_INDEX
: return "INDEX";
365 add_deprecated_token(GPtrArray
*deprecated
, const char *token
)
367 for (unsigned i
= 0; i
< deprecated
->len
; i
++) {
368 const char *str
= g_ptr_array_index(deprecated
, i
);
369 if (g_ascii_strcasecmp(token
, str
) == 0) {
370 /* It's already in our list */
374 g_ptr_array_add(deprecated
, g_strdup(token
));
378 add_compile_warning(dfwork_t
*dfw
, const char *format
, ...)
381 va_start(ap
, format
);
382 char *msg
= ws_strdup_vprintf(format
, ap
);
384 dfw
->warnings
= g_slist_prepend(dfw
->warnings
, msg
);
388 dfilter_expand(const char *expr
, df_error_t
**err_ret
)
390 return dfilter_macro_apply(expr
, err_ret
);
394 dfwork_parse(const char *expanded_text
, dfsyntax_t
*dfs
)
397 YY_BUFFER_STATE in_buffer
;
398 unsigned token_count
= 0;
401 if (df_yylex_init(&scanner
) != 0) {
402 dfs
->error
= df_error_new_printf(DF_ERROR_GENERIC
, NULL
, "Can't initialize scanner: %s", g_strerror(errno
));
406 in_buffer
= df_yy_scan_string(expanded_text
, scanner
);
407 df_yyset_extra(dfs
, scanner
);
410 if (dfs
->flags
& DF_DEBUG_FLEX
|| dfs
->flags
& DF_DEBUG_LEMON
) {
411 ws_message("Compile Wireshark without NDEBUG to enable Flex and/or Lemon debug traces");
414 /* Enable/disable debugging for Flex. */
415 df_yyset_debug(dfs
->flags
& DF_DEBUG_FLEX
, scanner
);
417 /* Enable/disable debugging for Lemon. */
418 DfilterTrace(dfs
->flags
& DF_DEBUG_LEMON
? stderr
: NULL
, "lemon> ");
422 token
= df_yylex(scanner
);
424 /* Check for scanner failure */
425 if (token
== SCAN_FAILED
) {
426 ws_noisy("Scanning failed");
427 ws_assert(dfs
->error
!= NULL
);
431 /* Check for end-of-input */
433 ws_noisy("Scanning finished");
437 ws_noisy("(%u) Token %d %s %s",
438 ++token_count
, token
, tokenstr(token
),
439 stnode_token(dfs
->lval
));
441 /* Give the token to the parser */
442 Dfilter(ParserObj
, token
, dfs
->lval
, dfs
);
443 /* The parser has freed the lval for us. */
452 /* Tell the parser that we have reached the end of input; that
453 * way, it'll reset its state for the next compile. (We want
454 * to do that even if we got a syntax error, to make sure the
455 * parser state is cleaned up; we don't create a new parser
456 * object when we start a new parse, and don't destroy it when
457 * the parse finishes.) */
458 Dfilter(ParserObj
, 0, NULL
, dfs
);
460 /* Free scanner state */
461 df_yy_delete_buffer(in_buffer
, scanner
);
462 df_yylex_destroy(scanner
);
464 return dfs
->error
== NULL
;
468 dfwork_build(dfwork_t
*dfw
)
473 log_syntax_tree(LOG_LEVEL_NOISY
, dfw
->st_root
, "Syntax tree before semantic check", NULL
);
475 /* Check semantics and do necessary type conversion*/
476 if (!dfw_semcheck(dfw
))
479 /* Cache tree representation in tree_str. */
481 log_syntax_tree(LOG_LEVEL_NOISY
, dfw
->st_root
, "Syntax tree after successful semantic check", &tree_str
);
483 if ((dfw
->flags
& DF_SAVE_TREE
) && tree_str
== NULL
) {
484 tree_str
= dump_syntax_tree_str(dfw
->st_root
);
487 /* Create bytecode */
490 /* Tuck away the bytecode in the dfilter_t */
491 dfilter
= dfilter_new(dfw
->deprecated
);
492 dfilter
->insns
= dfw
->insns
;
494 dfilter
->interesting_fields
= dfw_interesting_fields(dfw
,
495 &dfilter
->num_interesting_fields
);
496 dfilter
->expanded_text
= dfw
->expanded_text
;
497 dfw
->expanded_text
= NULL
;
498 dfilter
->references
= dfw
->references
;
499 dfw
->references
= NULL
;
500 dfilter
->raw_references
= dfw
->raw_references
;
501 dfw
->raw_references
= NULL
;
502 dfilter
->warnings
= dfw
->warnings
;
503 dfw
->warnings
= NULL
;
504 dfilter
->ret_type
= dfw
->ret_type
;
506 if (dfw
->flags
& DF_SAVE_TREE
) {
508 dfilter
->syntax_tree_str
= tree_str
;
512 dfilter
->syntax_tree_str
= NULL
;
517 /* Initialize run-time space */
518 dfilter
->num_registers
= dfw
->next_register
;
519 dfilter
->registers
= g_new0(df_cell_t
, dfilter
->num_registers
);
525 compile_filter(const char *expanded_text
, unsigned flags
, df_error_t
**err_ptr
)
527 dfsyntax_t
*dfs
= NULL
;
528 dfwork_t
*dfw
= NULL
;
529 dfilter_t
*dfcode
= NULL
;
530 df_error_t
*error
= NULL
;
533 dfs
= dfsyntax_new(flags
);
535 ok
= dfwork_parse(expanded_text
, dfs
);
541 else if (dfs
->st_root
== NULL
) {
542 /* Is it an empty filter? If so set the dfcode to NULL and return success.
543 * This can happen if the user clears the display filter toolbar in the UI.
544 * In that case the compilation succeeds and the NULL dfcode clears the filter
545 * (show all frames). */
551 dfw
= dfwork_new(expanded_text
, dfs
->flags
);
552 dfw
->st_root
= dfs
->st_root
;
554 dfw
->deprecated
= g_ptr_array_ref(dfs
->deprecated
);
558 dfcode
= dfwork_build(dfw
);
559 if (dfcode
== NULL
) {
570 if (error
== NULL
|| error
->msg
== NULL
) {
571 /* We require an error message. */
572 ws_critical("Unknown error compiling filter: %s", expanded_text
);
573 error
= df_error_new_msg("Unknown error compiling filter");
576 ws_assert(err_ptr
&& error
);
587 compile_failure(df_error_t
*error
, df_error_t
**err_ptr
)
590 ws_debug("Error compiling filter: (%d) %s", error
->code
, error
->msg
);
595 df_error_free(&error
);
601 dfilter_compile_full(const char *text
, dfilter_t
**dfp
,
602 df_error_t
**err_ptr
, unsigned flags
,
607 df_error_t
*error
= NULL
;
612 caller
= "(unknown)";
616 ws_warning("Called from %s() with invalid NULL expression", caller
);
618 *err_ptr
= df_error_new_msg("BUG: NULL text argument is invalid");
623 ws_debug("Called from %s() with filter: %s", caller
, text
);
625 if (flags
& DF_EXPAND_MACROS
) {
626 expanded_text
= dfilter_macro_apply(text
, &error
);
627 if (expanded_text
== NULL
) {
628 return compile_failure(error
, err_ptr
);
630 ws_noisy("Expanded text: %s", expanded_text
);
633 expanded_text
= g_strdup(text
);
634 ws_noisy("Verbatim text: %s", expanded_text
);
637 dfcode
= compile_filter(expanded_text
, flags
, &error
);
638 g_free(expanded_text
);
639 expanded_text
= NULL
;
642 return compile_failure(error
, err_ptr
);
646 ws_info("Compiled display filter: %s", text
);
650 struct stnode
*dfilter_get_syntax_tree(const char *text
)
652 dfsyntax_t
*dfs
= NULL
;
653 dfwork_t
*dfw
= NULL
;
655 dfs
= dfsyntax_new(DF_EXPAND_MACROS
);
657 char *expanded_text
= dfilter_macro_apply(text
, NULL
);
658 if (!expanded_text
) {
663 bool ok
= dfwork_parse(expanded_text
, dfs
);
664 if (!ok
|| !dfs
->st_root
) {
665 g_free(expanded_text
);
670 dfw
= dfwork_new(expanded_text
, dfs
->flags
);
671 dfw
->st_root
= dfs
->st_root
;
673 g_free(expanded_text
);
676 if (!dfw_semcheck(dfw
)) {
681 stnode_t
*st_root
= dfw
->st_root
;
689 dfilter_apply(dfilter_t
*df
, proto_tree
*tree
)
691 return dfvm_apply(df
, tree
);
695 dfilter_apply_edt(dfilter_t
*df
, epan_dissect_t
* edt
)
697 return dfvm_apply(df
, edt
->tree
);
701 dfilter_apply_full(dfilter_t
*df
, proto_tree
*tree
, GPtrArray
**fvals
)
703 return dfvm_apply_full(df
, tree
, fvals
);
707 dfilter_prime_proto_tree(const dfilter_t
*df
, proto_tree
*tree
)
711 for (i
= 0; i
< df
->num_interesting_fields
; i
++) {
712 proto_tree_prime_with_hfid(tree
, df
->interesting_fields
[i
]);
717 dfilter_prime_proto_tree_print(const dfilter_t
*df
, proto_tree
*tree
)
719 for (int i
= 0; i
< df
->num_interesting_fields
; i
++) {
720 proto_tree_prime_with_hfid_print(tree
, df
->interesting_fields
[i
]);
725 dfilter_has_interesting_fields(const dfilter_t
*df
)
727 return (df
->num_interesting_fields
> 0);
731 dfilter_interested_in_field(const dfilter_t
*df
, int hfid
)
735 for (i
= 0; i
< df
->num_interesting_fields
; i
++) {
736 if (df
->interesting_fields
[i
] == hfid
) {
744 dfilter_interested_in_proto(const dfilter_t
*df
, int proto_id
)
748 for (i
= 0; i
< df
->num_interesting_fields
; i
++) {
749 int df_hfid
= df
->interesting_fields
[i
];
750 if (proto_registrar_is_protocol(df_hfid
)) {
751 /* XXX: Should we go up to the parent of a pino?
752 * We can tell if df_hfid is a PINO, but there's
753 * no function to return the parent proto ID yet.
755 if (df_hfid
== proto_id
) {
759 if (proto_registrar_get_parent(df_hfid
) == proto_id
) {
768 dfilter_requires_columns(const dfilter_t
*df
)
774 /* XXX: Could cache this like packet_cache_proto_handles */
775 static int proto_cols
;
776 if (proto_cols
<= 0) {
777 proto_cols
= proto_get_id_by_filter_name("_ws.col");
779 ws_assert(proto_cols
> 0);
781 return dfilter_interested_in_proto(df
, proto_cols
);
785 dfilter_deprecated_tokens(dfilter_t
*df
) {
786 if (df
->deprecated
&& df
->deprecated
->len
> 0) {
787 return df
->deprecated
;
793 dfilter_get_warnings(dfilter_t
*df
)
799 dfilter_dump(FILE *fp
, dfilter_t
*df
, uint16_t flags
)
801 dfvm_dump(fp
, df
, flags
);
805 dfilter_text(dfilter_t
*df
)
807 return df
->expanded_text
;
811 dfilter_syntax_tree(dfilter_t
*df
)
813 return df
->syntax_tree_str
;
817 dfilter_get_return_type(dfilter_t
*df
)
823 dfilter_log_full(const char *domain
, enum ws_log_level level
,
824 const char *file
, long line
, const char *func
,
825 dfilter_t
*df
, const char *msg
)
827 if (!ws_log_msg_is_active(domain
, level
))
831 ws_log_write_always_full(domain
, level
, file
, line
, func
,
832 "%s: NULL display filter", msg
? msg
: "?");
836 char *str
= dfvm_dump_str(NULL
, df
, true);
837 if (G_UNLIKELY(msg
== NULL
))
838 ws_log_write_always_full(domain
, level
, file
, line
, func
, "\nFilter:\n %s\n\n%s", dfilter_text(df
), str
);
840 ws_log_write_always_full(domain
, level
, file
, line
, func
, "%s:\nFilter:\n %s\n\n%s", msg
, dfilter_text(df
), str
);
845 compare_ref_layer(const void *_a
, const void *_b
)
847 const df_reference_t
*a
= *(const df_reference_t
**)_a
;
848 const df_reference_t
*b
= *(const df_reference_t
**)_b
;
849 return a
->proto_layer_num
- b
->proto_layer_num
;
853 load_references(GHashTable
*table
, proto_tree
*tree
, bool raw
)
858 header_field_info
*hfinfo
;
861 if (g_hash_table_size(table
) == 0) {
866 g_hash_table_iter_init(&iter
, table
);
867 while (g_hash_table_iter_next(&iter
, (void **)&hfinfo
, (void **)&refs
)) {
868 /* If we have a previous array free the data */
869 g_ptr_array_set_size(refs
, 0);
872 finfos
= proto_find_finfo(tree
, hfinfo
->id
);
873 if (finfos
== NULL
) {
874 hfinfo
= hfinfo
->same_name_next
;
877 for (unsigned i
= 0; i
< finfos
->len
; i
++) {
878 finfo
= g_ptr_array_index(finfos
, i
);
879 g_ptr_array_add(refs
, reference_new(finfo
, raw
));
881 g_ptr_array_free(finfos
, true);
882 hfinfo
= hfinfo
->same_name_next
;
885 g_ptr_array_sort(refs
, compare_ref_layer
);
890 dfilter_load_field_references(const dfilter_t
*df
, proto_tree
*tree
)
892 load_references(df
->references
, tree
, false);
893 load_references(df
->raw_references
, tree
, true);
897 dfilter_load_field_references_edt(const dfilter_t
*df
, epan_dissect_t
*edt
)
899 dfilter_load_field_references(df
, edt
->tree
);
903 reference_new(const field_info
*finfo
, bool raw
)
905 df_reference_t
*ref
= g_new(df_reference_t
, 1);
906 ref
->hfinfo
= finfo
->hfinfo
;
908 ref
->value
= dfvm_get_raw_fvalue(finfo
);
911 ref
->value
= fvalue_dup(finfo
->value
);
913 ref
->proto_layer_num
= finfo
->proto_layer_num
;
918 reference_free(df_reference_t
*ref
)
920 fvalue_free(ref
->value
);
925 df_error_new(int code
, char *msg
, df_loc_t
*loc
)
927 df_error_t
*err
= g_new(df_error_t
, 1);
931 err
->loc
.col_start
= loc
->col_start
;
932 err
->loc
.col_len
= loc
->col_len
;
935 err
->loc
.col_start
= -1;
936 err
->loc
.col_len
= 0;
942 df_error_new_vprintf(int code
, df_loc_t
*loc
, const char *fmt
, va_list ap
)
944 df_error_t
*err
= g_new(df_error_t
, 1);
946 err
->msg
= ws_strdup_vprintf(fmt
, ap
);
948 err
->loc
.col_start
= loc
->col_start
;
949 err
->loc
.col_len
= loc
->col_len
;
952 err
->loc
.col_start
= -1;
953 err
->loc
.col_len
= 0;
959 df_error_new_printf(int code
, df_loc_t
*loc
, const char *fmt
, ...)
963 df_error_t
*err
= df_error_new_vprintf(code
, loc
, fmt
, ap
);
969 df_error_free(df_error_t
**ep
)
979 df_cell_append(df_cell_t
*rp
, fvalue_t
*fv
)
981 /* Assert cell has been initialized. */
982 ws_assert(rp
->array
!= NULL
);
983 g_ptr_array_add(rp
->array
, fv
);
987 df_cell_ref(df_cell_t
*rp
)
989 if (rp
->array
== NULL
)
991 return g_ptr_array_ref(rp
->array
);
995 df_cell_size(const df_cell_t
*rp
)
997 if (rp
->array
== NULL
)
999 return rp
->array
->len
;
1003 df_cell_array(const df_cell_t
*rp
)
1005 if (rp
->array
== NULL
)
1007 return (fvalue_t
**)rp
->array
->pdata
;
1011 df_cell_is_empty(const df_cell_t
*rp
)
1013 if (rp
->array
== NULL
)
1015 return rp
->array
->len
== 0;
1019 df_cell_is_null(const df_cell_t
*rp
)
1021 return rp
->array
== NULL
;
1025 df_cell_init(df_cell_t
*rp
, bool free_seg
)
1029 rp
->array
= g_ptr_array_new_with_free_func((GDestroyNotify
)fvalue_free
);
1031 rp
->array
= g_ptr_array_new();
1035 df_cell_clear(df_cell_t
*rp
)
1038 g_ptr_array_unref(rp
->array
);
1043 df_cell_iter_init(df_cell_t
*rp
, df_cell_iter_t
*iter
)
1045 iter
->ptr
= rp
->array
;
1050 df_cell_iter_next(df_cell_iter_t
*iter
)
1052 if (iter
->idx
< iter
->ptr
->len
) {
1053 return iter
->ptr
->pdata
[iter
->idx
++];
1059 * Editor modelines - https://www.wireshark.org/tools/modelines.html
1064 * indent-tabs-mode: t
1067 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
1068 * :indentSize=8:tabSize=8:noTabs=false: