forked from osmocom/wireshark
![Dario Lombardo](/assets/img/avatar_default.png)
Skipping dissectors dir for now. Change-Id: I717b66bfbc7cc81b83f8c2cbc011fcad643796aa Reviewed-on: https://code.wireshark.org/review/25694 Petri-Dish: Dario Lombardo <lomato@gmail.com> Tested-by: Petri Dish Buildbot Reviewed-by: Anders Broman <a.broman58@gmail.com>
696 lines
16 KiB
C
696 lines
16 KiB
C
/* dfilter-macro.c
|
|
*
|
|
* Wireshark - Network traffic analyzer
|
|
* By Gerald Combs <gerald@wireshark.org>
|
|
* Copyright 2001 Gerald Combs
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0-or-later
|
|
*/
|
|
|
|
|
|
#include "config.h"
|
|
|
|
#ifdef DUMP_DFILTER_MACRO
|
|
#include <stdio.h>
|
|
#include <wsutil/ws_printf.h> /* ws_debug_printf */
|
|
#endif
|
|
#include <string.h>
|
|
|
|
#include "dfilter-int.h"
|
|
#include "dfilter.h"
|
|
#include "dfilter-macro.h"
|
|
#include <ftypes/ftypes-int.h>
|
|
#include <epan/uat-int.h>
|
|
#include <epan/proto.h>
|
|
|
|
typedef struct {
|
|
const char* name;
|
|
gboolean usable;
|
|
char* repr;
|
|
} fvt_cache_entry_t;
|
|
|
|
static uat_t* dfilter_macro_uat = NULL;
|
|
static dfilter_macro_t* macros = NULL;
|
|
static guint num_macros;
|
|
static GHashTable* fvt_cache = NULL;
|
|
|
|
/* #define DUMP_DFILTER_MACRO */
|
|
#ifdef DUMP_DFILTER_MACRO
|
|
void dump_dfilter_macro_t(const dfilter_macro_t *m, const char *function, const char *file, int line);
|
|
#define DUMP_MACRO(m) dump_dfilter_macro_t(m, G_STRFUNC, __FILE__, __LINE__)
|
|
#else
|
|
#define DUMP_MACRO(m)
|
|
#endif
|
|
|
|
static gboolean fvt_cache_cb(proto_node * node, gpointer data _U_) {
|
|
field_info* finfo = PNODE_FINFO(node);
|
|
fvt_cache_entry_t* e;
|
|
|
|
if (!finfo) return FALSE;
|
|
|
|
if ((e = (fvt_cache_entry_t*)g_hash_table_lookup(fvt_cache,finfo->hfinfo->abbrev))) {
|
|
e->usable = FALSE;
|
|
} else if (finfo->value.ftype->val_to_string_repr) {
|
|
switch (finfo->hfinfo->type) {
|
|
case FT_NONE:
|
|
case FT_PROTOCOL:
|
|
return FALSE;
|
|
default:
|
|
break;
|
|
}
|
|
e = g_new(fvt_cache_entry_t,1);
|
|
e->name = finfo->hfinfo->abbrev;
|
|
e->repr = fvalue_to_string_repr(NULL, &(finfo->value), FTREPR_DFILTER, finfo->hfinfo->display);
|
|
e->usable = TRUE;
|
|
g_hash_table_insert(fvt_cache,(void*)finfo->hfinfo->abbrev,e);
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
static void dfilter_free_fvt_entry(gpointer v)
|
|
{
|
|
fvt_cache_entry_t* e = (fvt_cache_entry_t*)v;
|
|
wmem_free(NULL, e->repr);
|
|
g_free(e);
|
|
}
|
|
|
|
void dfilter_macro_build_ftv_cache(void* tree_root) {
|
|
g_hash_table_remove_all(fvt_cache);
|
|
proto_tree_traverse_post_order((proto_tree *)tree_root, fvt_cache_cb, NULL);
|
|
}
|
|
|
|
static gchar* dfilter_macro_resolve(gchar* name, gchar** args, gchar** error) {
|
|
GString* text;
|
|
int argc = 0;
|
|
dfilter_macro_t* m = NULL;
|
|
fvt_cache_entry_t* e;
|
|
int* arg_pos_p;
|
|
gchar** parts;
|
|
gchar* ret;
|
|
guint i;
|
|
|
|
for (i = 0; i < num_macros; i++) {
|
|
dfilter_macro_t* c = &(macros[i]);
|
|
if ( c->usable && g_str_equal(c->name,name) ) {
|
|
m = c;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!m) {
|
|
if (fvt_cache &&
|
|
(e = (fvt_cache_entry_t *)g_hash_table_lookup(fvt_cache,name)) != NULL) {
|
|
if(e->usable) {
|
|
return wmem_strdup(NULL, e->repr);
|
|
} else {
|
|
if (error != NULL)
|
|
*error = g_strdup_printf("macro '%s' is unusable", name);
|
|
return NULL;
|
|
}
|
|
} else {
|
|
if (error != NULL)
|
|
*error = g_strdup_printf("macro '%s' does not exist", name);
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
DUMP_MACRO(m);
|
|
|
|
if (args) {
|
|
while(args[argc]) argc++;
|
|
}
|
|
|
|
if (argc != m->argc) {
|
|
if (error != NULL) {
|
|
*error = g_strdup_printf("wrong number of arguments for macro '%s', expecting %d instead of %d",
|
|
name, m->argc, argc);
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
arg_pos_p = m->args_pos;
|
|
parts = m->parts;
|
|
|
|
text = g_string_new(*(parts++));
|
|
|
|
if (args) {
|
|
while (*parts) {
|
|
g_string_append_printf(text,"%s%s",
|
|
args[*(arg_pos_p++)],
|
|
*(parts++));
|
|
}
|
|
}
|
|
|
|
ret = wmem_strdup(NULL, text->str);
|
|
|
|
g_string_free(text,TRUE);
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
static gchar* dfilter_macro_apply_recurse(const gchar* text, guint depth, gchar** error) {
|
|
enum { OUTSIDE, STARTING, NAME, ARGS } state = OUTSIDE;
|
|
GString* out;
|
|
GString* name = NULL;
|
|
GString* arg = NULL;
|
|
GPtrArray* args = NULL;
|
|
gchar c;
|
|
const gchar* r = text;
|
|
gboolean changed = FALSE;
|
|
|
|
if ( depth > 31) {
|
|
if (error != NULL)
|
|
*error = g_strdup("too much nesting in macros");
|
|
return NULL;
|
|
}
|
|
|
|
#define FGS(n) if (n) g_string_free(n,TRUE); n = NULL
|
|
|
|
#define FREE_ALL() \
|
|
do { \
|
|
FGS(name); \
|
|
FGS(arg); \
|
|
if (args) { \
|
|
while(args->len) { void* p = g_ptr_array_remove_index_fast(args,0); g_free(p); } \
|
|
g_ptr_array_free(args,TRUE); \
|
|
args = NULL; \
|
|
} \
|
|
} while(0)
|
|
|
|
if (error != NULL)
|
|
*error = NULL;
|
|
out = g_string_sized_new(64);
|
|
|
|
while(1) {
|
|
c = *r++;
|
|
|
|
switch(state) {
|
|
case OUTSIDE: {
|
|
switch(c) {
|
|
case '\0': {
|
|
goto finish;
|
|
} case '$': {
|
|
state = STARTING;
|
|
break;
|
|
} default: {
|
|
g_string_append_c(out,c);
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
} case STARTING: {
|
|
switch (c) {
|
|
case '{': {
|
|
args = g_ptr_array_new();
|
|
arg = g_string_sized_new(32);
|
|
name = g_string_sized_new(32);
|
|
|
|
state = NAME;
|
|
|
|
break;
|
|
} case '\0': {
|
|
g_string_append_c(out,'$');
|
|
|
|
goto finish;
|
|
} default: {
|
|
g_string_append_c(out,'$');
|
|
g_string_append_c(out,c);
|
|
|
|
state = OUTSIDE;
|
|
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
} case NAME: {
|
|
if ( g_ascii_isalnum(c) || c == '_' || c == '-' || c == '.' ) {
|
|
g_string_append_c(name,c);
|
|
} else if ( c == ':') {
|
|
state = ARGS;
|
|
} else if ( c == '}') {
|
|
gchar* resolved;
|
|
|
|
g_ptr_array_add(args,NULL);
|
|
|
|
resolved = dfilter_macro_resolve(name->str, (gchar**)args->pdata, error);
|
|
if (resolved == NULL)
|
|
goto on_error;
|
|
|
|
changed = TRUE;
|
|
|
|
g_string_append(out,resolved);
|
|
wmem_free(NULL, resolved);
|
|
|
|
FREE_ALL();
|
|
|
|
state = OUTSIDE;
|
|
} else if ( c == '\0') {
|
|
if (error != NULL)
|
|
*error = g_strdup("end of filter in the middle of a macro expression");
|
|
goto on_error;
|
|
} else {
|
|
if (error != NULL)
|
|
*error = g_strdup("invalid character in macro name");
|
|
goto on_error;
|
|
}
|
|
break;
|
|
} case ARGS: {
|
|
switch(c) {
|
|
case '\0': {
|
|
if (error != NULL)
|
|
*error = g_strdup("end of filter in the middle of a macro expression");
|
|
goto on_error;
|
|
} case ';': {
|
|
g_ptr_array_add(args,g_string_free(arg,FALSE));
|
|
|
|
arg = g_string_sized_new(32);
|
|
break;
|
|
} case '\\': {
|
|
c = *r++;
|
|
if (c) {
|
|
g_string_append_c(arg,c);
|
|
break;
|
|
} else {
|
|
if (error != NULL)
|
|
*error = g_strdup("end of filter in the middle of a macro expression");
|
|
goto on_error;
|
|
}
|
|
} default: {
|
|
g_string_append_c(arg,c);
|
|
break;
|
|
} case '}': {
|
|
gchar* resolved;
|
|
g_ptr_array_add(args,g_string_free(arg,FALSE));
|
|
g_ptr_array_add(args,NULL);
|
|
|
|
arg = NULL;
|
|
|
|
resolved = dfilter_macro_resolve(name->str, (gchar**)args->pdata, error);
|
|
if (resolved == NULL)
|
|
goto on_error;
|
|
|
|
changed = TRUE;
|
|
|
|
g_string_append(out,resolved);
|
|
wmem_free(NULL, resolved);
|
|
|
|
FREE_ALL();
|
|
|
|
state = OUTSIDE;
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
finish:
|
|
{
|
|
FREE_ALL();
|
|
|
|
if (changed) {
|
|
gchar* resolved = dfilter_macro_apply_recurse(out->str, depth + 1, error);
|
|
g_string_free(out,TRUE);
|
|
return resolved;
|
|
} else {
|
|
gchar* out_str = wmem_strdup(NULL, out->str);
|
|
g_string_free(out,TRUE);
|
|
return out_str;
|
|
}
|
|
}
|
|
on_error:
|
|
{
|
|
FREE_ALL();
|
|
if (error != NULL) {
|
|
if (*error == NULL)
|
|
*error = g_strdup("unknown error in macro expression");
|
|
}
|
|
g_string_free(out,TRUE);
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
gchar* dfilter_macro_apply(const gchar* text, gchar** error) {
|
|
return dfilter_macro_apply_recurse(text, 0, error);
|
|
}
|
|
|
|
static gboolean macro_update(void* mp, gchar** error) {
|
|
dfilter_macro_t* m = (dfilter_macro_t*)mp;
|
|
GPtrArray* parts;
|
|
GArray* args_pos;
|
|
const gchar* r;
|
|
gchar* w;
|
|
gchar* part;
|
|
int argc = 0;
|
|
|
|
DUMP_MACRO(m);
|
|
|
|
*error = NULL;
|
|
|
|
/* Invalidate the display filter in case it's in use */
|
|
if (dfilter_macro_uat && dfilter_macro_uat->post_update_cb)
|
|
dfilter_macro_uat->post_update_cb();
|
|
|
|
parts = g_ptr_array_new();
|
|
args_pos = g_array_new(FALSE,FALSE,sizeof(int));
|
|
|
|
m->priv = part = w = g_strdup(m->text);
|
|
r = m->text;
|
|
g_ptr_array_add(parts,part);
|
|
|
|
while (r && *r) {
|
|
|
|
switch (*r) {
|
|
default:
|
|
*(w++) = *(r++);
|
|
break;
|
|
case '\0':
|
|
*w = *r;
|
|
goto done;
|
|
case '\\':
|
|
*(w++) = *(++r);
|
|
r++;
|
|
break;
|
|
case '$': {
|
|
int cnt = 0;
|
|
int arg_pos = 0;
|
|
do {
|
|
char c = *(r+1);
|
|
if (c >= '0' && c <= '9') {
|
|
cnt++;
|
|
r++;
|
|
*(w++) = '\0';
|
|
arg_pos *= 10;
|
|
arg_pos += c - '0';
|
|
} else {
|
|
break;
|
|
}
|
|
} while(*r);
|
|
|
|
if (cnt) {
|
|
*(w++) = '\0';
|
|
r++;
|
|
argc = argc < arg_pos ? arg_pos : argc;
|
|
arg_pos--;
|
|
g_array_append_val(args_pos,arg_pos);
|
|
g_ptr_array_add(parts,w);
|
|
} else {
|
|
*(w++) = *(r++);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
done:
|
|
g_ptr_array_add(parts,NULL);
|
|
|
|
g_free(m->parts);
|
|
m->parts = (gchar**)parts->pdata;
|
|
|
|
g_free(m->args_pos);
|
|
m->args_pos = (int*)(void *)args_pos->data;
|
|
|
|
g_ptr_array_free(parts,FALSE);
|
|
g_array_free(args_pos,FALSE);
|
|
|
|
m->argc = argc;
|
|
|
|
m->usable = TRUE;
|
|
|
|
DUMP_MACRO(m);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static void macro_free(void* r) {
|
|
dfilter_macro_t* m = (dfilter_macro_t*)r;
|
|
|
|
DUMP_MACRO(r);
|
|
|
|
g_free(m->name);
|
|
g_free(m->text);
|
|
g_free(m->priv);
|
|
g_free(m->parts);
|
|
g_free(m->args_pos);
|
|
}
|
|
|
|
static void* macro_copy(void* dest, const void* orig, size_t len _U_) {
|
|
dfilter_macro_t* d = (dfilter_macro_t*)dest;
|
|
const dfilter_macro_t* m = (const dfilter_macro_t*)orig;
|
|
|
|
DUMP_MACRO(m);
|
|
|
|
d->name = g_strdup(m->name);
|
|
d->text = g_strdup(m->text);
|
|
d->usable = m->usable;
|
|
|
|
if (m->parts) {
|
|
guint nparts = 0;
|
|
|
|
/*
|
|
* Copy the contents of m->priv (a "cooked" version
|
|
* of m->text) into d->priv.
|
|
*
|
|
* First we clone m->text into d->priv, this gets
|
|
* us a NUL terminated string of the proper length.
|
|
*
|
|
* Then we loop copying bytes from m->priv into
|
|
* d-priv. Since m->priv contains internal ACSII NULs
|
|
* we use the length of m->text to stop the copy.
|
|
*/
|
|
|
|
d->priv = g_strdup(m->text);
|
|
{
|
|
const gchar* oldText = m->text;
|
|
const gchar* oldPriv = (const gchar*)m->priv;
|
|
gchar* newPriv = (gchar*)d->priv;
|
|
while(oldText && *oldText) {
|
|
*(newPriv++) = *(oldPriv++);
|
|
oldText++;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* The contents of the m->parts array contains pointers
|
|
* into various sections of m->priv. Since it's
|
|
* an argv style array of ponters, this array is
|
|
* actually one larger than the number of parts
|
|
* to hold the final NULL terminator.
|
|
*
|
|
* The following copy clones the original m->parts
|
|
* array into d->parts but then fixes-up the pointers
|
|
* so that they point into the appropriate sections
|
|
* of the d->priv.
|
|
*/
|
|
|
|
do nparts++; while (m->parts[nparts]);
|
|
d->parts = (gchar **)g_memdup(m->parts,(nparts+1)*(guint)sizeof(void*));
|
|
nparts = 0;
|
|
while(m->parts[nparts]) {
|
|
if(nparts) {
|
|
d->parts[nparts] = d->parts[nparts - 1] + (m->parts[nparts] - m->parts[nparts - 1]);
|
|
} else {
|
|
d->parts[nparts] = (gchar *)d->priv;
|
|
}
|
|
nparts++;
|
|
}
|
|
|
|
/*
|
|
* Clone the contents of m->args_pos into d->args_pos.
|
|
*/
|
|
|
|
d->args_pos = (int *)g_memdup(m->args_pos,(--nparts)*(guint)sizeof(int));
|
|
}
|
|
|
|
DUMP_MACRO(d);
|
|
|
|
return d;
|
|
}
|
|
|
|
static gboolean macro_name_chk(void *mp, const char *in_name, guint name_len,
|
|
const void *u1 _U_, const void *u2 _U_, char **error) {
|
|
dfilter_macro_t* m = (dfilter_macro_t*)mp;
|
|
guint i;
|
|
|
|
if (name_len == 0) {
|
|
*error = g_strdup("invalid name");
|
|
return FALSE;
|
|
}
|
|
|
|
for (i=0; i < name_len; i++) {
|
|
if (!(in_name[i] == '_' || g_ascii_isalnum(in_name[i]) ) ) {
|
|
*error = g_strdup("invalid char in name");
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
/* When loading (!m->name) or when adding/changing the an item with a
|
|
* different name, check for uniqueness. NOTE: if a duplicate already
|
|
* exists (because the user manually edited the file), then this will
|
|
* not trigger a warning. */
|
|
if (!m->name || g_strcmp0(m->name, in_name)) {
|
|
for (i = 0; i < num_macros; i++) {
|
|
/* This a string field which is always NUL-terminated,
|
|
* so no need to check name_len. */
|
|
if (!g_strcmp0(in_name, macros[i].name)) {
|
|
*error = g_strdup_printf("macro '%s' already exists",
|
|
in_name);
|
|
return FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
UAT_CSTRING_CB_DEF(macro,name,dfilter_macro_t)
|
|
UAT_CSTRING_CB_DEF(macro,text,dfilter_macro_t)
|
|
|
|
void dfilter_macro_init(void) {
|
|
static uat_field_t uat_fields[] = {
|
|
UAT_FLD_CSTRING_OTHER(macro,name,"Name",macro_name_chk,"The name of the macro."),
|
|
/* N.B. it would be nice if there was a field type for display filters (with
|
|
auto-completion & colouring), but this wouldn't work here as the filter string
|
|
will contain $1, etc... */
|
|
UAT_FLD_CSTRING_ISPRINT(macro,text,"Text","The text this macro resolves to."),
|
|
UAT_END_FIELDS
|
|
};
|
|
|
|
dfilter_macro_uat = uat_new("Display Filter Macros",
|
|
sizeof(dfilter_macro_t),
|
|
DFILTER_MACRO_FILENAME,
|
|
TRUE,
|
|
¯os,
|
|
&num_macros,
|
|
0, /* doesn't affect anything that requires a GUI update */
|
|
"ChDisplayFilterMacrosSection",
|
|
macro_copy,
|
|
macro_update,
|
|
macro_free,
|
|
NULL, /* Note: This is set in macros_init () */
|
|
NULL,
|
|
uat_fields);
|
|
|
|
fvt_cache = g_hash_table_new_full(g_str_hash,g_str_equal, NULL, dfilter_free_fvt_entry);
|
|
}
|
|
|
|
void dfilter_macro_get_uat(uat_t **dfmu_ptr_ptr) {
|
|
*dfmu_ptr_ptr = dfilter_macro_uat;
|
|
}
|
|
|
|
#ifdef DUMP_DFILTER_MACRO
|
|
/*
|
|
* The dfilter_macro_t has several characteristics that are
|
|
* not immediately obvious. The dump_dfilter_filter_macro_t()
|
|
* function can be used to help "visualize" the contents of
|
|
* a dfilter_macro_t.
|
|
*
|
|
* Some non-obvious components of this struct include:
|
|
*
|
|
* m->parts is an argv style array of pointers into the
|
|
* m->priv string.
|
|
*
|
|
* The last pointer of an m->parts array should contain
|
|
* NULL to indicate the end of the parts pointer array.
|
|
*
|
|
* m->priv is a "cooked" copy of the m->text string.
|
|
* Any variable substitution indicators within m->text
|
|
* ("$1", "$2", ...) will have been replaced with ASCII
|
|
* NUL characters within m->priv.
|
|
*
|
|
* The first element of m->parts array (m-parts[0]) will
|
|
* usually have the same pointer value as m->priv (unless
|
|
* the dfilter-macro starts off with a variable
|
|
* substitution indicator (e.g. "$1").
|
|
*/
|
|
|
|
void dump_dfilter_macro_t(const dfilter_macro_t *m, const char *function, const char *file, int line)
|
|
{
|
|
ws_debug_printf("\n<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
|
|
|
|
if(m == NULL) {
|
|
ws_debug_printf(" dfilter_macro_t * == NULL! (via: %s(): %s:%d)\n", function, file, line);
|
|
ws_debug_printf("\n>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
|
|
}
|
|
|
|
ws_debug_printf("DUMP of dfilter_macro_t: %p (via: %s(): %s:%d)\n", m, function, file, line);
|
|
|
|
ws_debug_printf(" &dfilter_macro->name == %p\n", &m->name);
|
|
if(m->name == NULL) {
|
|
ws_debug_printf(" ->name == NULL\n");
|
|
} else {
|
|
ws_debug_printf(" ->name == %p\n", m->name);
|
|
ws_debug_printf(" ->name == <%s>\n", m->name);
|
|
}
|
|
|
|
ws_debug_printf(" &dfilter_macro->text == %p\n", &m->text);
|
|
if(m->text == NULL) {
|
|
ws_debug_printf(" ->text == NULL\n");
|
|
} else {
|
|
ws_debug_printf(" ->text == %p\n", m->text);
|
|
ws_debug_printf(" ->text == <%s>\n", m->text);
|
|
}
|
|
|
|
ws_debug_printf(" &dfilter_macro->usable == %p\n", &m->usable);
|
|
ws_debug_printf(" ->usable == %u\n", m->usable);
|
|
|
|
ws_debug_printf(" &dfilter_macro->parts == %p\n", &m->parts);
|
|
|
|
if(m->parts == NULL) {
|
|
ws_debug_printf(" ->parts == NULL\n");
|
|
} else {
|
|
int i = 0;
|
|
|
|
while (m->parts[i]) {
|
|
ws_debug_printf(" ->parts[%d] == %p\n", i, m->parts[i]);
|
|
ws_debug_printf(" ->parts[%d] == <%s>\n", i, m->parts[i]);
|
|
i++;
|
|
}
|
|
ws_debug_printf(" ->parts[%d] == NULL\n", i);
|
|
}
|
|
|
|
ws_debug_printf(" &dfilter_macro->args_pos == %p\n", &m->args_pos);
|
|
if(m->args_pos == NULL) {
|
|
ws_debug_printf(" ->args_pos == NULL\n");
|
|
} else {
|
|
ws_debug_printf(" ->args_pos == %p\n", m->args_pos);
|
|
/*ws_debug_printf(" ->args_pos == <%?>\n", m->args_pos);*/
|
|
}
|
|
|
|
ws_debug_printf(" &dfilter_macro->argc == %p\n", &m->argc);
|
|
ws_debug_printf(" ->argc == %d\n", m->argc);
|
|
|
|
ws_debug_printf(" &dfilter_macro->priv == %p\n", &m->priv);
|
|
if(m->priv == NULL) {
|
|
ws_debug_printf(" ->priv == NULL\n");
|
|
} else {
|
|
ws_debug_printf(" ->priv == %p\n", m->priv);
|
|
ws_debug_printf(" ->priv == <%s>\n", (char *)m->priv);
|
|
}
|
|
|
|
ws_debug_printf("\n>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
|
|
}
|
|
#endif
|
|
|
|
void dfilter_macro_cleanup(void)
|
|
{
|
|
g_hash_table_destroy(fvt_cache);
|
|
}
|
|
|
|
/*
|
|
* Editor modelines - http://www.wireshark.org/tools/modelines.html
|
|
*
|
|
* Local variables:
|
|
* c-basic-offset: 8
|
|
* tab-width: 8
|
|
* indent-tabs-mode: t
|
|
* End:
|
|
*
|
|
* vi: set shiftwidth=8 tabstop=8 noexpandtab:
|
|
* :indentSize=8:tabSize=8:noTabs=false:
|
|
*/
|