regen pidl all: rm epan/dissectors/pidl/*-stamp; pushd epan/dissectors/pidl/ && make...
[wireshark-sm.git] / epan / dfilter / dfunctions.c
blobef6f7092dc8930901a97ca6ff9018753116c34d4
1 /*
2 * Wireshark - Network traffic analyzer
4 * Copyright 2006 Gilbert Ramirez <gram@alumni.rice.edu>
6 * SPDX-License-Identifier: GPL-2.0-or-later
7 */
9 #include "config.h"
10 #define WS_LOG_DOMAIN LOG_DOMAIN_DFILTER
12 #include <wireshark.h>
14 #include "dfilter-int.h"
15 #include "dfunctions.h"
16 #include "dfilter-plugin.h"
17 #include "sttype-field.h"
18 #include "sttype-pointer.h"
19 #include "semcheck.h"
21 #include <string.h>
23 #include <ftypes/ftypes.h>
24 #include <epan/exceptions.h>
25 #include <wsutil/ws_assert.h>
28 static GHashTable *registered_functions;
30 static GPtrArray *registered_names;
32 /* Convert an FT_STRING using a callback function */
33 static bool
34 string_walk(GSList *stack, uint32_t arg_count _U_, df_cell_t *retval, char(*conv_func)(char))
36 GPtrArray *arg1;
37 fvalue_t *arg_fvalue;
38 fvalue_t *new_ft_string;
39 const wmem_strbuf_t *src;
40 wmem_strbuf_t *dst;
42 ws_assert(arg_count == 1);
43 arg1 = stack->data;
44 if (arg1 == NULL)
45 return false;
47 for (unsigned i = 0; i < arg1->len; i++) {
48 arg_fvalue = arg1->pdata[i];
49 /* XXX - it would be nice to handle FT_TVBUFF, too */
50 if (FT_IS_STRING(fvalue_type_ftenum(arg_fvalue))) {
51 src = fvalue_get_strbuf(arg_fvalue);
52 dst = wmem_strbuf_new_sized(NULL, src->len);
53 for (size_t j = 0; j < src->len; j++) {
54 wmem_strbuf_append_c(dst, conv_func(src->str[j]));
56 new_ft_string = fvalue_new(FT_STRING);
57 fvalue_set_strbuf(new_ft_string, dst);
58 df_cell_append(retval, new_ft_string);
62 return true;
65 /* dfilter function: lower() */
66 static bool
67 df_func_lower(GSList *stack, uint32_t arg_count, df_cell_t *retval)
69 return string_walk(stack, arg_count, retval, g_ascii_tolower);
72 /* dfilter function: upper() */
73 static bool
74 df_func_upper(GSList *stack, uint32_t arg_count, df_cell_t *retval)
76 return string_walk(stack, arg_count, retval, g_ascii_toupper);
79 /* dfilter function: count() */
80 static bool
81 df_func_count(GSList *stack, uint32_t arg_count _U_, df_cell_t *retval)
83 GPtrArray *arg1;
84 fvalue_t *ft_ret;
85 uint32_t num_items;
87 ws_assert(arg_count == 1);
88 arg1 = stack->data;
89 if (arg1 == NULL)
90 return false;
92 num_items = arg1->len;
93 ft_ret = fvalue_new(FT_UINT32);
94 fvalue_set_uinteger(ft_ret, num_items);
95 df_cell_append(retval, ft_ret);
97 return true;
100 /* dfilter function: string() */
101 static bool
102 df_func_string(GSList *stack, uint32_t arg_count _U_, df_cell_t *retval)
104 GPtrArray *arg1;
105 fvalue_t *arg_fvalue;
106 fvalue_t *new_ft_string;
107 char *s;
109 ws_assert(arg_count == 1);
110 arg1 = stack->data;
111 if (arg1 == NULL)
112 return false;
114 for (unsigned i = 0; i < arg1->len; i++) {
115 arg_fvalue = arg1->pdata[i];
116 switch (fvalue_type_ftenum(arg_fvalue))
118 case FT_UINT8:
119 case FT_UINT16:
120 case FT_UINT24:
121 case FT_UINT32:
122 case FT_UINT40:
123 case FT_UINT48:
124 case FT_UINT56:
125 case FT_UINT64:
126 case FT_INT8:
127 case FT_INT16:
128 case FT_INT32:
129 case FT_INT40:
130 case FT_INT48:
131 case FT_INT56:
132 case FT_INT64:
133 case FT_IPv4:
134 case FT_IPv6:
135 case FT_FLOAT:
136 case FT_DOUBLE:
137 case FT_ETHER:
138 case FT_FRAMENUM:
139 case FT_AX25:
140 case FT_IPXNET:
141 case FT_GUID:
142 case FT_OID:
143 case FT_EUI64:
144 case FT_VINES:
145 case FT_REL_OID:
146 case FT_SYSTEM_ID:
147 case FT_FCWWN:
148 case FT_IEEE_11073_SFLOAT:
149 case FT_IEEE_11073_FLOAT:
150 s = fvalue_to_string_repr(NULL, arg_fvalue, FTREPR_DFILTER, BASE_NONE);
151 /* Ensure we have an allocated string here */
152 if (!s)
153 s = wmem_strdup(NULL, "");
154 break;
155 default:
156 return true;
159 new_ft_string = fvalue_new(FT_STRING);
160 fvalue_set_string(new_ft_string, s);
161 wmem_free(NULL, s);
162 df_cell_append(retval, new_ft_string);
165 return true;
168 /* dfilter function: double() */
169 static bool
170 df_func_double(GSList *stack, uint32_t arg_count _U_, df_cell_t *retval)
172 GPtrArray *arg1;
173 fvalue_t *arg_fvalue;
174 fvalue_t *new_ft_double;
175 double res;
177 ws_assert(arg_count == 1);
178 arg1 = stack->data;
179 if (arg1 == NULL)
180 return false;
182 for (unsigned i = 0; i < arg1->len; i++) {
183 arg_fvalue = arg1->pdata[i];
185 if (fvalue_to_double(arg_fvalue, &res) == FT_OK) {
186 new_ft_double = fvalue_new(FT_DOUBLE);
187 fvalue_set_floating(new_ft_double, res);
188 df_cell_append(retval, new_ft_double);
192 if (df_cell_size(retval) == 0) {
193 return false;
196 return true;
199 /* dfilter function: float() */
200 static bool
201 df_func_float(GSList *stack, uint32_t arg_count _U_, df_cell_t *retval)
203 GPtrArray *arg1;
204 fvalue_t *arg_fvalue;
205 fvalue_t *new_ft_double;
206 double res;
208 ws_assert(arg_count == 1);
209 arg1 = stack->data;
210 if (arg1 == NULL)
211 return false;
213 for (unsigned i = 0; i < arg1->len; i++) {
214 arg_fvalue = arg1->pdata[i];
216 if (fvalue_to_double(arg_fvalue, &res) == FT_OK) {
217 new_ft_double = fvalue_new(FT_FLOAT);
218 fvalue_set_floating(new_ft_double, (float)res);
219 df_cell_append(retval, new_ft_double);
223 if (df_cell_size(retval) == 0) {
224 return false;
227 return true;
230 /* dfilter functions: dec(), hex(), */
231 static bool
232 df_func_base(GSList *stack, uint32_t arg_count _U_, df_cell_t *retval, int base)
234 GPtrArray *arg1;
235 fvalue_t *arg_fvalue;
236 fvalue_t *new_ft_string;
237 char *s;
239 ws_assert(arg_count == 1);
240 arg1 = stack->data;
241 if (arg1 == NULL)
242 return false;
244 for (unsigned i = 0; i < arg1->len; i++) {
245 arg_fvalue = arg1->pdata[i];
247 if (FT_IS_UINT(fvalue_type_ftenum(arg_fvalue))) {
248 s = fvalue_to_string_repr(NULL, arg_fvalue, FTREPR_DFILTER, base);
249 /* Ensure we have an allocated string here */
250 if (!s)
251 s = wmem_strdup(NULL, "");
252 } else {
253 /* XXX - We have, unfortunately, some field abbreviations which are
254 * re-used with incompatible types, some of which support different
255 * bases and some which don't.
257 s = wmem_strdup(NULL, "");
260 new_ft_string = fvalue_new(FT_STRING);
261 fvalue_set_string(new_ft_string, s);
262 wmem_free(NULL, s);
263 df_cell_append(retval, new_ft_string);
266 return true;
269 static bool
270 df_func_hex(GSList *stack, uint32_t arg_count _U_, df_cell_t *retval)
272 return df_func_base(stack, arg_count, retval, BASE_HEX);
275 static bool
276 df_func_dec(GSList *stack, uint32_t arg_count _U_, df_cell_t *retval)
278 return df_func_base(stack, arg_count, retval, BASE_DEC);
281 #if 0
282 // XXX - BASE_OCT isn't handled by fvalue_to_string_repr; it probably
283 // should at least for FTREPR_DISPLAY (the filter language doesn't
284 // support it due to possible notation confusion, I assume.)
285 // Add that first before offering it.
286 static bool
287 df_func_oct(GSList *stack, uint32_t arg_count _U_, df_cell_t *retval)
289 return df_func_base(stack, arg_count, retval, BASE_OCT);
291 #endif
293 static bool
294 df_func_compare(GSList *stack, uint32_t arg_count, df_cell_t *retval,
295 ft_bool_t (*fv_cmp)(const fvalue_t *a, const fvalue_t *b))
297 fvalue_t *fv_ret = NULL;
298 GSList *args;
299 GPtrArray *arg1;
300 fvalue_t *arg_fvalue;
301 uint32_t i;
303 for (args = stack, i = 0; i < arg_count; args = args->next, i++) {
304 arg1 = args->data;
305 if (arg1 != NULL) {
306 for (unsigned j = 0; j < arg1->len; j++) {
307 arg_fvalue = arg1->pdata[j];
308 if (fv_ret == NULL || (fv_cmp(arg_fvalue, fv_ret) == FT_TRUE)) {
309 fv_ret = arg_fvalue;
315 if (fv_ret == NULL)
316 return false;
318 df_cell_append(retval, fvalue_dup(fv_ret));
320 return true;
323 /* Find maximum value. */
324 static bool
325 df_func_max(GSList *stack, uint32_t arg_count, df_cell_t *retval)
327 return df_func_compare(stack, arg_count, retval, fvalue_gt);
330 /* Find minimum value. */
331 static bool
332 df_func_min(GSList *stack, uint32_t arg_count, df_cell_t *retval)
334 return df_func_compare(stack, arg_count, retval, fvalue_lt);
337 static bool
338 df_func_abs(GSList *stack, uint32_t arg_count _U_, df_cell_t *retval)
340 GPtrArray *arg1;
341 fvalue_t *fv_arg, *new_fv;
342 char *err_msg = NULL;
344 ws_assert(arg_count == 1);
345 arg1 = stack->data;
346 if (arg1 == NULL)
347 return false;
349 for (unsigned i = 0; i < arg1->len; i++) {
350 fv_arg = arg1->pdata[i];
351 if (fvalue_is_negative(fv_arg)) {
352 new_fv = fvalue_unary_minus(fv_arg, &err_msg);
353 if (new_fv == NULL) {
354 ws_debug("abs: %s", err_msg);
355 g_free(err_msg);
356 err_msg = NULL;
359 else {
360 new_fv = fvalue_dup(fv_arg);
362 df_cell_append(retval, new_fv);
365 return !df_cell_is_empty(retval);
368 ftenum_t
369 df_semcheck_param(dfwork_t *dfw, const char *func_name _U_, ftenum_t logical_ftype,
370 stnode_t *param, df_loc_t func_loc _U_)
372 ftenum_t ftype = FT_NONE;
374 resolve_unparsed(dfw, param, false);
376 switch (stnode_type_id(param)) {
377 case STTYPE_ARITHMETIC:
378 ftype = check_arithmetic(dfw, param, logical_ftype);
379 break;
381 case STTYPE_LITERAL:
382 dfilter_fvalue_from_literal(dfw, logical_ftype, param, false, NULL);
383 ftype = sttype_pointer_ftenum(param);
384 break;
386 case STTYPE_STRING:
387 dfilter_fvalue_from_string(dfw, logical_ftype, param, NULL);
388 ftype = sttype_pointer_ftenum(param);
389 break;
391 case STTYPE_CHARCONST:
392 dfilter_fvalue_from_charconst(dfw, logical_ftype, param);
393 ftype = sttype_pointer_ftenum(param);
394 break;
396 case STTYPE_NUMBER:
397 dfilter_fvalue_from_number(dfw, logical_ftype, param);
398 ftype = sttype_pointer_ftenum(param);
399 break;
401 case STTYPE_FUNCTION:
402 ftype = check_function(dfw, param, logical_ftype);
403 break;
405 case STTYPE_FIELD:
406 dfw->field_count++;
407 /* fall-through */
408 case STTYPE_REFERENCE:
409 ftype = sttype_field_ftenum(param);
410 break;
412 case STTYPE_SLICE:
413 ftype = check_slice(dfw, param, logical_ftype);
414 break;
416 case STTYPE_UNPARSED:
417 case STTYPE_TEST:
418 case STTYPE_FVALUE:
419 case STTYPE_PCRE:
420 case STTYPE_SET:
421 case STTYPE_UNINITIALIZED:
422 case STTYPE_NUM_TYPES:
423 ASSERT_STTYPE_NOT_REACHED(stnode_type_id(param));
426 return ftype;
429 /* For upper() and lower() checks that the parameter passed to
430 * it is an FT_STRING */
431 static ftenum_t
432 ul_semcheck_is_string(dfwork_t *dfw, const char *func_name, ftenum_t logical_ftype _U_,
433 GSList *param_list, df_loc_t func_loc _U_)
435 ws_assert(g_slist_length(param_list) == 1);
436 stnode_t *param = param_list->data;
437 ftenum_t ftype;
439 resolve_unparsed(dfw, param, true);
441 ftype = df_semcheck_param(dfw, func_name, logical_ftype, param, func_loc);
442 if (!FT_IS_STRING(ftype)) {
443 dfunc_fail(dfw, param, "Only string type fields can be used as parameter for %s()", func_name);
445 return FT_STRING;
448 static ftenum_t
449 ul_semcheck_is_field(dfwork_t *dfw, const char *func_name, ftenum_t logical_ftype _U_,
450 GSList *param_list, df_loc_t func_loc _U_)
452 ws_assert(g_slist_length(param_list) == 1);
453 stnode_t *param = param_list->data;
455 resolve_unparsed(dfw, param, true);
457 if (stnode_type_id(param) != STTYPE_FIELD) {
458 dfunc_fail(dfw, param, "Only fields can be used as parameter for %s()", func_name);
460 df_semcheck_param(dfw, func_name, logical_ftype, param, func_loc);
461 return FT_UINT32;
464 static ftenum_t
465 ul_semcheck_can_length(dfwork_t *dfw, const char *func_name, ftenum_t logical_ftype,
466 GSList *param_list, df_loc_t func_loc)
468 ws_assert(g_slist_length(param_list) == 1);
469 stnode_t *param = param_list->data;
470 ftenum_t ftype;
472 ftype = df_semcheck_param(dfw, func_name, logical_ftype, param, func_loc);
473 if (!ftype_can_length(ftype)) {
474 dfunc_fail(dfw, param, "Argument does not support the %s() function", func_name);
476 return FT_UINT32;
479 static ftenum_t
480 ul_semcheck_string(dfwork_t *dfw, const char *func_name, ftenum_t logical_ftype _U_,
481 GSList *param_list, df_loc_t func_loc _U_)
483 header_field_info *hfinfo;
485 ws_assert(g_slist_length(param_list) == 1);
486 stnode_t *param = param_list->data;
488 resolve_unparsed(dfw, param, true);
490 if (stnode_type_id(param) == STTYPE_FIELD) {
491 dfw->field_count++;
492 hfinfo = sttype_field_hfinfo(param);
493 switch (hfinfo->type) {
494 case FT_UINT8:
495 case FT_UINT16:
496 case FT_UINT24:
497 case FT_UINT32:
498 case FT_UINT40:
499 case FT_UINT48:
500 case FT_UINT56:
501 case FT_UINT64:
502 case FT_INT8:
503 case FT_INT16:
504 case FT_INT32:
505 case FT_INT40:
506 case FT_INT48:
507 case FT_INT56:
508 case FT_INT64:
509 case FT_IPv4:
510 case FT_IPv6:
511 case FT_FLOAT:
512 case FT_DOUBLE:
513 case FT_ETHER:
514 case FT_FRAMENUM:
515 case FT_AX25:
516 case FT_IPXNET:
517 case FT_GUID:
518 case FT_OID:
519 case FT_EUI64:
520 case FT_VINES:
521 case FT_REL_OID:
522 case FT_SYSTEM_ID:
523 case FT_FCWWN:
524 case FT_IEEE_11073_SFLOAT:
525 case FT_IEEE_11073_FLOAT:
526 return FT_STRING;
527 default:
528 break;
530 dfunc_fail(dfw, param, "String conversion for field \"%s\" is not supported", hfinfo->abbrev);
532 dfunc_fail(dfw, param, "Only fields can be used as parameter for %s()", func_name);
535 static ftenum_t
536 ul_semcheck_double(dfwork_t *dfw, const char *func_name, ftenum_t logical_ftype,
537 GSList *param_list, df_loc_t func_loc)
539 ws_assert(g_slist_length(param_list) == 1);
540 stnode_t *param = param_list->data;
541 ftenum_t ftype;
543 ftype = df_semcheck_param(dfw, func_name, logical_ftype, param, func_loc);
544 if (!ftype_can_val_to_double(ftype)) {
545 dfunc_fail(dfw, param, "Argument does not support the %s() function", func_name);
547 return FT_DOUBLE;
550 static ftenum_t
551 ul_semcheck_base(dfwork_t *dfw, const char *func_name, ftenum_t logical_ftype _U_,
552 GSList *param_list, df_loc_t func_loc _U_)
554 header_field_info *hfinfo;
556 ws_assert(g_slist_length(param_list) == 1);
557 stnode_t *param = param_list->data;
559 resolve_unparsed(dfw, param, true);
561 if (stnode_type_id(param) == STTYPE_FIELD) {
562 dfw->field_count++;
563 hfinfo = sttype_field_hfinfo(param);
564 /* FT_CHAR also supports BASE_, but for what sort of escaped
565 * values to use for non-printable ASCII. BASE_HEX uses hex,
566 * all other bases will use octal.
567 * That's a little confusing, so don't support it for now.
568 * More useful might be to display all possible values as
569 * HEX or DEC, i.e. convert to a FT_UINT8 first. */
570 if (FT_IS_UINT(hfinfo->type)) {
571 return FT_STRING;
573 dfunc_fail(dfw, param, "Base conversion for field \"%s\" is not supported", hfinfo->abbrev);
575 dfunc_fail(dfw, param, "Only fields can be used as parameter for %s()", func_name);
578 static ftenum_t
579 ul_semcheck_value_string(dfwork_t *dfw, const char *func_name, ftenum_t logical_ftype _U_,
580 GSList *param_list, df_loc_t func_loc _U_)
582 header_field_info *hfinfo;
584 ws_assert(g_slist_length(param_list) == 1);
585 stnode_t *param = param_list->data;
587 resolve_unparsed(dfw, param, true);
589 if (stnode_type_id(param) == STTYPE_FIELD) {
590 dfw->field_count++;
591 hfinfo = sttype_field_hfinfo(param);
592 /* XXX - We should check all fields with the same abbreviation. */
593 if (hfinfo->strings != NULL && hfinfo->type != FT_FRAMENUM && hfinfo->type != FT_PROTOCOL) {
594 sttype_field_set_value_string(param, true);
595 return FT_STRING;
597 dfunc_fail(dfw, param, "Field \"%s\" does not have a value string.",
598 hfinfo->abbrev);
600 dfunc_fail(dfw, param, "Only fields can be used as parameter for %s()", func_name);
603 /* Check arguments are all the same type and they can be compared. */
604 static ftenum_t
605 ul_semcheck_compare(dfwork_t *dfw, const char *func_name, ftenum_t logical_ftype,
606 GSList *param_list, df_loc_t func_loc)
608 stnode_t *param;
609 ftenum_t ftype;
610 GSList *l;
612 for (l = param_list; l != NULL; l = l->next) {
613 param = l->data;
614 ftype = df_semcheck_param(dfw, func_name, logical_ftype, param, func_loc);
616 if (!compatible_ftypes(ftype, logical_ftype)) {
617 dfunc_fail(dfw, param, "Arguments to '%s' must be of compatible type (expected %s, got %s)",
618 func_name, ftype_pretty_name(logical_ftype), ftype_pretty_name(ftype));
620 if (!ftype_can_cmp(ftype)) {
621 dfunc_fail(dfw, param, "Argument '%s' to '%s' cannot be ordered",
622 stnode_todisplay(param), func_name);
626 return logical_ftype;
629 static ftenum_t
630 ul_semcheck_absolute_value(dfwork_t *dfw, const char *func_name, ftenum_t logical_ftype,
631 GSList *param_list, df_loc_t func_loc)
633 ws_assert(g_slist_length(param_list) == 1);
634 stnode_t *param = param_list->data;
635 ftenum_t ftype;
637 ftype = df_semcheck_param(dfw, func_name, logical_ftype, param, func_loc);
638 if (!ftype_can_is_negative(ftype) || !ftype_can_unary_minus(ftype)) {
639 dfunc_fail(dfw, param, "Argument cannot be negated");
641 return ftype;
644 /* The table of all display-filter functions */
645 static df_func_def_t
646 df_functions[] = {
647 { "lower", df_func_lower, 1, 1, FT_STRING, ul_semcheck_is_string },
648 { "upper", df_func_upper, 1, 1, FT_STRING, ul_semcheck_is_string },
649 /* Length function is implemented as a DFVM instruction. */
650 { "len", NULL, 1, 1, FT_UINT32, ul_semcheck_can_length },
651 { "count", df_func_count, 1, 1, FT_UINT32, ul_semcheck_is_field },
652 { "string", df_func_string, 1, 1, FT_STRING, ul_semcheck_string },
653 { "float", df_func_float, 1, 1, FT_FLOAT, ul_semcheck_double },
654 { "double", df_func_double, 1, 1, FT_DOUBLE, ul_semcheck_double },
655 { "dec", df_func_dec, 1, 1, FT_STRING, ul_semcheck_base },
656 { "hex", df_func_hex, 1, 1, FT_STRING, ul_semcheck_base },
657 //{ "oct", df_func_oct, 1, 1, FT_STRING, ul_semcheck_base },
658 /* VALUE STRING function is implemented as a DFVM instruction. */
659 { "vals", NULL, 1, 1, FT_STRING, ul_semcheck_value_string },
660 { "max", df_func_max, 1, 0, FT_NONE, ul_semcheck_compare },
661 { "min", df_func_min, 1, 0, FT_NONE, ul_semcheck_compare },
662 { "abs", df_func_abs, 1, 1, FT_NONE, ul_semcheck_absolute_value },
663 { NULL, NULL, 0, 0, FT_NONE, NULL }
666 /* Returns NULL for success. */
667 static const char *
668 check_valid_func_name(const char *name)
670 if (!g_ascii_isalpha(name[0]) && name[0] != '_') {
671 return "first character must be a letter or underscore";
673 for (int i = 1; name[i] != '\0'; i++) {
674 if (!g_ascii_isalnum(name[0]) && name[0] != '_') {
675 return "function names must be alphanumeric plus underscore";
678 return NULL;
681 void
682 df_func_init(void)
684 df_func_def_t *func;
686 registered_functions = g_hash_table_new(g_str_hash, g_str_equal);
687 registered_names = g_ptr_array_new();
689 /* Register built-in functions. */
690 for (func = df_functions; func->name != NULL; func++) {
691 df_func_register(func);
695 bool
696 df_func_register(df_func_def_t *func)
698 ws_assert(registered_functions);
699 ws_assert(registered_names);
700 const char *err;
701 if ((err = check_valid_func_name(func->name)) != NULL) {
702 ws_critical("Function name \"%s\" is invalid: %s",
703 func->name, err);
704 return false;
706 if (g_hash_table_contains(registered_functions, func->name)) {
707 ws_critical("Trying to register display filter function \"%s\" but "
708 "it already exists", func->name);
709 return false;
712 g_ptr_array_add(registered_names, (gpointer)func->name);
713 return g_hash_table_insert(registered_functions, (gpointer)func->name, func);
716 bool
717 df_func_deregister(df_func_def_t *func)
719 ws_assert(registered_functions);
720 df_func_def_t *value;
722 value = g_hash_table_lookup(registered_functions, func->name);
723 if (value != func) {
724 ws_critical("Trying to deregister display filter function name \"%s\" but "
725 "it doesn't match the existing function", func->name);
726 return false;
729 g_ptr_array_remove_fast(registered_names, (void *)func->name);
730 return g_hash_table_remove(registered_functions, func->name);
733 /* Lookup a display filter function record by name */
734 df_func_def_t*
735 df_func_lookup(const char *name)
737 return g_hash_table_lookup(registered_functions, name);
740 GPtrArray *
741 df_func_name_list(void)
743 return g_ptr_array_ref(registered_names);
746 void
747 df_func_cleanup(void)
749 g_hash_table_destroy(registered_functions);
750 registered_functions = NULL;
751 g_ptr_array_unref(registered_names);
752 registered_names = NULL;
756 * Editor modelines - https://www.wireshark.org/tools/modelines.html
758 * Local variables:
759 * c-basic-offset: 4
760 * tab-width: 8
761 * indent-tabs-mode: nil
762 * End:
764 * vi: set shiftwidth=4 tabstop=8 expandtab:
765 * :indentSize=4:tabSize=8:noTabs=true: