aboutsummaryrefslogtreecommitdiffstats
path: root/epan
diff options
context:
space:
mode:
authorGilbert Ramirez <gram@alumni.rice.edu>2006-05-02 14:26:17 +0000
committerGilbert Ramirez <gram@alumni.rice.edu>2006-05-02 14:26:17 +0000
commite3899ed4a43f006d51724d1fa05be20050968bd1 (patch)
tree3b6937dd3cfc7e7374855f1142c0bfcea1b1c49f /epan
parent7edd136c889356810028c6fb291d8db69298beab (diff)
Add infrastructure for display filter functions.
Add upper() and lower() display filter functions for string fields. svn path=/trunk/; revision=18071
Diffstat (limited to 'epan')
-rw-r--r--epan/dfilter/Makefile.am4
-rw-r--r--epan/dfilter/Makefile.nmake2
-rw-r--r--epan/dfilter/dfunctions.c158
-rw-r--r--epan/dfilter/dfunctions.h56
-rw-r--r--epan/dfilter/dfvm.c32
-rw-r--r--epan/dfilter/dfvm.h9
-rw-r--r--epan/dfilter/gencode.c169
-rw-r--r--epan/dfilter/grammar.lemon43
-rw-r--r--epan/dfilter/scanner.l21
-rw-r--r--epan/dfilter/semcheck.c169
-rw-r--r--epan/dfilter/sttype-function.c125
-rw-r--r--epan/dfilter/sttype-function.h42
-rw-r--r--epan/dfilter/syntax-tree.c1
-rw-r--r--epan/dfilter/syntax-tree.h2
-rw-r--r--epan/ftypes/ftype-bytes.c5
-rw-r--r--epan/ftypes/ftype-double.c2
-rw-r--r--epan/ftypes/ftype-guid.c1
-rw-r--r--epan/ftypes/ftype-integer.c13
-rw-r--r--epan/ftypes/ftype-ipv4.c1
-rw-r--r--epan/ftypes/ftype-none.c1
-rw-r--r--epan/ftypes/ftype-pcre.c2
-rw-r--r--epan/ftypes/ftype-string.c3
-rw-r--r--epan/ftypes/ftype-time.c2
-rw-r--r--epan/ftypes/ftype-tvbuff.c1
-rw-r--r--epan/ftypes/ftypes.c7
-rw-r--r--epan/ftypes/ftypes.h4
26 files changed, 819 insertions, 56 deletions
diff --git a/epan/dfilter/Makefile.am b/epan/dfilter/Makefile.am
index 139c5a661d..7e1614320d 100644
--- a/epan/dfilter/Makefile.am
+++ b/epan/dfilter/Makefile.am
@@ -46,6 +46,8 @@ libdfilter_la_SOURCES = \
dfilter.c \
dfilter.h \
dfilter-int.h \
+ dfunctions.c \
+ dfunctions.h \
dfvm.c \
dfvm.h \
drange.c \
@@ -59,6 +61,8 @@ libdfilter_la_SOURCES = \
scanner.c \
semcheck.c \
semcheck.h \
+ sttype-function.c \
+ sttype-function.h \
sttype-integer.c \
sttype-pointer.c \
sttype-range.c \
diff --git a/epan/dfilter/Makefile.nmake b/epan/dfilter/Makefile.nmake
index 8593e39dbe..38ac1d7c53 100644
--- a/epan/dfilter/Makefile.nmake
+++ b/epan/dfilter/Makefile.nmake
@@ -20,6 +20,7 @@ CVARSDLL=-DWIN32 -DNULL=0 -D_MT -D_DLL
OBJECTS = \
dfilter.obj \
+ dfunctions.obj \
dfvm.obj \
drange.obj \
gencode.obj \
@@ -27,6 +28,7 @@ OBJECTS = \
grammar.obj \
scanner.obj \
semcheck.obj \
+ sttype-function.obj \
sttype-integer.obj \
sttype-pointer.obj \
sttype-range.obj \
diff --git a/epan/dfilter/dfunctions.c b/epan/dfilter/dfunctions.c
new file mode 100644
index 0000000000..1b949b2ea5
--- /dev/null
+++ b/epan/dfilter/dfunctions.c
@@ -0,0 +1,158 @@
+/*
+ * $Id$
+ *
+ * Ethereal - Network traffic analyzer
+ *
+ * Copyright 2006 Gilbert Ramirez <gram@alumni.rice.edu>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <glib.h>
+
+#include "dfunctions.h"
+#include "dfilter-int.h"
+
+#include <string.h>
+#include <ctype.h>
+
+#include <ftypes/ftypes.h>
+#include <epan/exceptions.h>
+
+/* lowercase an ASCII character.
+ * (thanks to Guy Harris for the function) */
+static gchar
+string_ascii_to_lower(gchar c)
+{
+ return ((c & 0x80) ? c : tolower(c));
+}
+
+/* uppercase an ASCII character. */
+static gchar
+string_ascii_to_upper(gchar c)
+{
+ return ((c & 0x80) ? c : toupper(c));
+}
+
+
+/* Convert an FT_STRING using a callback function */
+static gboolean
+string_walk(GList* arg1list, GList **retval, gchar(*conv_func)(gchar))
+{
+ GList *arg1;
+ fvalue_t *arg_fvalue;
+ fvalue_t *new_ft_string;
+ char *s, *c;
+
+ arg1 = arg1list;
+ while (arg1) {
+ arg_fvalue = arg1->data;
+ switch (fvalue_ftype(arg_fvalue)->ftype) {
+ case FT_STRING:
+ s = g_strdup(fvalue_get(arg1->data));
+ for (c = s; *c; c++) {
+ /**c = string_ascii_to_lower(*c);*/
+ *c = conv_func(*c);
+ }
+
+ new_ft_string = fvalue_new(FT_STRING);
+ fvalue_set(new_ft_string, s, TRUE);
+ *retval = g_list_append(*retval, new_ft_string);
+ break;
+
+ /* XXX - it would be nice to handle FT_TVBUFF, too */
+
+ default:
+ break;
+ }
+ arg1 = arg1->next;
+ }
+
+ return TRUE;
+}
+
+/* dfilter function: lower() */
+static gboolean
+df_func_lower(GList* arg1list, GList *arg2junk _U_, GList **retval)
+{
+ return string_walk(arg1list, retval, string_ascii_to_lower);
+}
+
+/* dfilter function: upper() */
+static gboolean
+df_func_upper(GList* arg1list, GList *arg2junk _U_, GList **retval)
+{
+ return string_walk(arg1list, retval, string_ascii_to_upper);
+}
+
+/* For upper() and lower(), checks that the parameter passed to
+ * it is an FT_STRING */
+static void
+ul_semcheck_params(int param_num, stnode_t *st_node)
+{
+ sttype_id_t type;
+ ftenum_t ftype;
+ header_field_info *hfinfo;
+
+ type = stnode_type_id(st_node);
+
+ if (param_num == 0) {
+ switch(type) {
+ case STTYPE_FIELD:
+ hfinfo = stnode_data(st_node);
+ ftype = hfinfo->type;
+ if (ftype != FT_STRING && ftype != FT_STRINGZ
+ && ftype != FT_UINT_STRING) {
+ dfilter_fail("Only strings can be used in upper() or lower()");
+ THROW(TypeError);
+ }
+ break;
+ default:
+ dfilter_fail("Only string-type fields can be used in upper() or lower()");
+ THROW(TypeError);
+ }
+ }
+ else {
+ g_assert_not_reached();
+ }
+}
+
+/* The table of all display-filter functions */
+static df_func_def_t
+df_functions[] = {
+ { "lower", df_func_lower, FT_STRING, 1, 1, ul_semcheck_params },
+ { "upper", df_func_upper, FT_STRING, 1, 1, ul_semcheck_params },
+ { NULL, NULL, 0, 0, 0, NULL }
+};
+
+/* Lookup a display filter function record by name */
+df_func_def_t*
+df_func_lookup(char *name)
+{
+ df_func_def_t *func_def;
+
+ func_def = df_functions;
+ while (func_def->function != NULL) {
+ if (strcmp(func_def->name, name) == 0) {
+ return func_def;
+ }
+ func_def++;
+ }
+ return NULL;
+}
diff --git a/epan/dfilter/dfunctions.h b/epan/dfilter/dfunctions.h
new file mode 100644
index 0000000000..3e7ca3f0de
--- /dev/null
+++ b/epan/dfilter/dfunctions.h
@@ -0,0 +1,56 @@
+/*
+ * $Id$
+ *
+ * Ethereal - Network traffic analyzer
+ *
+ * Copyright 2006 Gilbert Ramirez <gram@alumni.rice.edu>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef DFUNCTIONS_H
+#define DFUNCTIONS_H
+
+#include <glib.h>
+#include <ftypes/ftypes.h>
+#include "syntax-tree.h"
+
+/* The run-time logic of the dfilter function */
+typedef gboolean (*DFFuncType)(GList *arg1list, GList *arg2list, GList **retval);
+
+/* The semantic check for the dfilter function */
+typedef void (*DFSemCheckType)(int param_num, stnode_t *st_node);
+
+/* If a function needs more args than this, increase
+ * this macro and add more arg members to the dfvm_insn_t
+ * struct in dfvm.h, and add some logic to dfw_append_function()
+ * and dfvm_apply() */
+#define DFUNCTION_MAX_NARGS 2
+
+/* This is a "function definition" record, holding everything
+ * we need to know about a function */
+typedef struct {
+ char *name;
+ DFFuncType function;
+ ftenum_t retval_ftype;
+ guint min_nargs;
+ guint max_nargs;
+ DFSemCheckType semcheck_param_function;
+} df_func_def_t;
+
+/* Return the function definition record for a function of named "name" */
+df_func_def_t* df_func_lookup(char *name);
+
+#endif
diff --git a/epan/dfilter/dfvm.c b/epan/dfilter/dfvm.c
index eb1521e8e5..ad3a467243 100644
--- a/epan/dfilter/dfvm.c
+++ b/epan/dfilter/dfvm.c
@@ -118,6 +118,18 @@ dfvm_dump(FILE *f, GPtrArray *insns)
arg2->value.numeric);
break;
+ case CALL_FUNCTION:
+ fprintf(f, "%05d CALL_FUNCTION\t%s (",
+ id, arg1->value.funcdef->name);
+ if (arg3) {
+ fprintf(f, "reg#%u", arg3->value.numeric);
+ }
+ if (arg4) {
+ fprintf(f, ", reg#%u", arg4->value.numeric);
+ }
+ fprintf(f, ") --> reg#%u\n", arg2->value.numeric);
+ break;
+
case PUT_FVALUE:
value_str = fvalue_to_string_repr(arg1->value.fvalue,
FTREPR_DFILTER, NULL);
@@ -373,8 +385,11 @@ dfvm_apply(dfilter_t *df, proto_tree *tree)
dfvm_insn_t *insn;
dfvm_value_t *arg1;
dfvm_value_t *arg2;
- dfvm_value_t *arg3;
+ dfvm_value_t *arg3 = NULL;
+ dfvm_value_t *arg4 = NULL;
header_field_info *hfinfo;
+ GList *param1;
+ GList *param2;
g_assert(tree);
@@ -414,6 +429,21 @@ dfvm_apply(dfilter_t *df, proto_tree *tree)
arg1->value.hfinfo, arg2->value.numeric);
break;
+ case CALL_FUNCTION:
+ arg3 = insn->arg3;
+ arg4 = insn->arg4;
+ param1 = NULL;
+ param2 = NULL;
+ if (arg3) {
+ param1 = df->registers[arg3->value.numeric];
+ }
+ if (arg4) {
+ param2 = df->registers[arg4->value.numeric];
+ }
+ accum = arg1->value.funcdef->function(param1, param2,
+ &df->registers[arg2->value.numeric]);
+ break;
+
case PUT_FVALUE:
accum = put_fvalue(df,
arg1->value.fvalue, arg2->value.numeric);
diff --git a/epan/dfilter/dfvm.h b/epan/dfilter/dfvm.h
index 862bb0a313..da773b7759 100644
--- a/epan/dfilter/dfvm.h
+++ b/epan/dfilter/dfvm.h
@@ -28,6 +28,7 @@
#include "dfilter-int.h"
#include "syntax-tree.h"
#include "drange.h"
+#include "dfunctions.h"
typedef enum {
EMPTY,
@@ -36,7 +37,8 @@ typedef enum {
INSN_NUMBER,
REGISTER,
INTEGER,
- DRANGE
+ DRANGE,
+ FUNCTION_DEF
} dfvm_value_type_t;
typedef struct {
@@ -47,6 +49,7 @@ typedef struct {
guint32 numeric;
drange *drange;
header_field_info *hfinfo;
+ df_func_def_t *funcdef;
} value;
} dfvm_value_t;
@@ -70,13 +73,13 @@ typedef enum {
ANY_BITWISE_AND,
ANY_CONTAINS,
ANY_MATCHES,
- MK_RANGE
+ MK_RANGE,
+ CALL_FUNCTION
} dfvm_opcode_t;
typedef struct {
int id;
- int LHS;
dfvm_opcode_t op;
dfvm_value_t *arg1;
dfvm_value_t *arg2;
diff --git a/epan/dfilter/gencode.c b/epan/dfilter/gencode.c
index c48329ba2f..7d3ef8c162 100644
--- a/epan/dfilter/gencode.c
+++ b/epan/dfilter/gencode.c
@@ -30,11 +30,15 @@
#include "syntax-tree.h"
#include "sttype-range.h"
#include "sttype-test.h"
+#include "sttype-function.h"
#include "ftypes/ftypes.h"
static void
gencode(dfwork_t *dfw, stnode_t *st_node);
+static int
+gen_entity(dfwork_t *dfw, stnode_t *st_arg, dfvm_value_t **p_jmp);
+
static void
dfw_append_insn(dfwork_t *dfw, dfvm_insn_t *insn)
{
@@ -155,58 +159,98 @@ dfw_append_mk_range(dfwork_t *dfw, stnode_t *node)
return reg;
}
+/* returns register number that the functions's result will be in. */
+static int
+dfw_append_function(dfwork_t *dfw, stnode_t *node, dfvm_value_t **p_jmp)
+{
+ GSList *params;
+ int i, num_params, reg;
+ dfvm_value_t **jmps;
+ dfvm_insn_t *insn;
+ dfvm_value_t *val1, *val2, *val;
+
+ params = sttype_function_params(node);
+ num_params = g_slist_length(params);
+
+ /* Array to hold the instructions that need to jump to
+ * an instruction if they fail. */
+ jmps = g_malloc(num_params * sizeof(dfvm_value_t*));
+
+ /* Create the new DFVM instruction */
+ insn = dfvm_insn_new(CALL_FUNCTION);
+
+ val1 = dfvm_value_new(FUNCTION_DEF);
+ val1->value.funcdef = sttype_function_funcdef(node);
+ insn->arg1 = val1;
+ val2 = dfvm_value_new(REGISTER);
+ val2->value.numeric = dfw->next_register++;
+ insn->arg2 = val2;
+ insn->arg3 = NULL;
+ insn->arg4 = NULL;
+
+ i = 0;
+ while (params) {
+ jmps[i] = NULL;
+ reg = gen_entity(dfw, params->data, &jmps[i]);
+
+ val = dfvm_value_new(REGISTER);
+ val->value.numeric = reg;
+
+ switch(i) {
+ case 0:
+ insn->arg3 = val;
+ break;
+ case 1:
+ insn->arg4 = val;
+ break;
+ default:
+ g_assert_not_reached();
+ }
+
+ params = params->next;
+ i++;
+ }
+
+ dfw_append_insn(dfw, insn);
+
+ /* If any of our parameters failed, send them to
+ * our own failure instruction. This *has* to be done
+ * after we caled dfw_append_insn above so that
+ * we know what the next DFVM insruction is, via
+ * dfw->next_insn_id */
+ for (i = 0; i < num_params; i++) {
+ if (jmps[i]) {
+ jmps[i]->value.numeric = dfw->next_insn_id;
+ }
+ }
+
+ /* We need another instruction to jump to another exit
+ * place, if the call() of our function failed for some reaosn */
+ insn = dfvm_insn_new(IF_FALSE_GOTO);
+ g_assert(p_jmp);
+ *p_jmp = dfvm_value_new(INSN_NUMBER);
+ insn->arg1 = *p_jmp;
+ dfw_append_insn(dfw, insn);
+
+ g_free(jmps);
+
+ return val2->value.numeric;
+}
+
static void
gen_relation(dfwork_t *dfw, dfvm_opcode_t op, stnode_t *st_arg1, stnode_t *st_arg2)
{
- sttype_id_t type1, type2;
dfvm_insn_t *insn;
dfvm_value_t *val1, *val2;
dfvm_value_t *jmp1 = NULL, *jmp2 = NULL;
int reg1 = -1, reg2 = -1;
- header_field_info *hfinfo;
- type1 = stnode_type_id(st_arg1);
- type2 = stnode_type_id(st_arg2);
-
- if (type1 == STTYPE_FIELD) {
- hfinfo = stnode_data(st_arg1);
- reg1 = dfw_append_read_tree(dfw, hfinfo);
-
- insn = dfvm_insn_new(IF_FALSE_GOTO);
- jmp1 = dfvm_value_new(INSN_NUMBER);
- insn->arg1 = jmp1;
- dfw_append_insn(dfw, insn);
- }
- else if (type1 == STTYPE_FVALUE) {
- reg1 = dfw_append_put_fvalue(dfw, stnode_data(st_arg1));
- }
- else if (type1 == STTYPE_RANGE) {
- reg1 = dfw_append_mk_range(dfw, st_arg1);
- }
- else {
- g_assert_not_reached();
- }
-
- if (type2 == STTYPE_FIELD) {
- hfinfo = stnode_data(st_arg2);
- reg2 = dfw_append_read_tree(dfw, hfinfo);
-
- insn = dfvm_insn_new(IF_FALSE_GOTO);
- jmp2 = dfvm_value_new(INSN_NUMBER);
- insn->arg1 = jmp2;
- dfw_append_insn(dfw, insn);
- }
- else if (type2 == STTYPE_FVALUE) {
- reg2 = dfw_append_put_fvalue(dfw, stnode_data(st_arg2));
- }
- else if (type2 == STTYPE_RANGE) {
- reg2 = dfw_append_mk_range(dfw, st_arg2);
- }
- else {
- g_assert_not_reached();
- }
+ /* Create code for the LHS and RHS of the relation */
+ reg1 = gen_entity(dfw, st_arg1, &jmp1);
+ reg2 = gen_entity(dfw, st_arg2, &jmp2);
+ /* Then combine them in a DFVM insruction */
insn = dfvm_insn_new(op);
val1 = dfvm_value_new(REGISTER);
val1->value.numeric = reg1;
@@ -216,6 +260,8 @@ gen_relation(dfwork_t *dfw, dfvm_opcode_t op, stnode_t *st_arg1, stnode_t *st_ar
insn->arg2 = val2;
dfw_append_insn(dfw, insn);
+ /* If either of the relation argumnents need an "exit" instruction
+ * to jump to (on failure), mark them */
if (jmp1) {
jmp1->value.numeric = dfw->next_insn_id;
}
@@ -225,6 +271,45 @@ gen_relation(dfwork_t *dfw, dfvm_opcode_t op, stnode_t *st_arg1, stnode_t *st_ar
}
}
+/* Parse an entity, returning the reg that it gets put into.
+ * p_jmp will be set if it has to be set by the calling code; it should
+ * be set tothe place to jump to, to return to the calling code,
+ * if the load of a field from the proto_tree fails. */
+static int
+gen_entity(dfwork_t *dfw, stnode_t *st_arg, dfvm_value_t **p_jmp)
+{
+ sttype_id_t e_type;
+ dfvm_insn_t *insn;
+ header_field_info *hfinfo;
+ e_type = stnode_type_id(st_arg);
+ int reg = -1;
+
+ if (e_type == STTYPE_FIELD) {
+ hfinfo = stnode_data(st_arg);
+ reg = dfw_append_read_tree(dfw, hfinfo);
+
+ insn = dfvm_insn_new(IF_FALSE_GOTO);
+ g_assert(p_jmp);
+ *p_jmp = dfvm_value_new(INSN_NUMBER);
+ insn->arg1 = *p_jmp;
+ dfw_append_insn(dfw, insn);
+ }
+ else if (e_type == STTYPE_FVALUE) {
+ reg = dfw_append_put_fvalue(dfw, stnode_data(st_arg));
+ }
+ else if (e_type == STTYPE_RANGE) {
+ reg = dfw_append_mk_range(dfw, st_arg);
+ }
+ else if (e_type == STTYPE_FUNCTION) {
+ reg = dfw_append_function(dfw, st_arg, p_jmp);
+ }
+ else {
+ printf("sttype_id is %u\n", e_type);
+ g_assert_not_reached();
+ }
+ return reg;
+}
+
static void
gen_test(dfwork_t *dfw, stnode_t *st_node)
diff --git a/epan/dfilter/grammar.lemon b/epan/dfilter/grammar.lemon
index 08169369c2..225dd73110 100644
--- a/epan/dfilter/grammar.lemon
+++ b/epan/dfilter/grammar.lemon
@@ -9,6 +9,7 @@
#include "syntax-tree.h"
#include "sttype-range.h"
#include "sttype-test.h"
+#include "sttype-function.h"
#include "drange.h"
#include "grammar.h"
@@ -51,6 +52,9 @@
%type drnode_list {GSList*}
%destructor drnode_list {drange_node_free_list($$);}
+%type funcparams {GSList*}
+%destructor funcparams {st_funcparams_free($$);}
+
/* This is called as soon as a syntax error happens. After that,
any "error" symbols are shifted, if possible. */
%syntax_error {
@@ -85,6 +89,9 @@ any "error" symbols are shifted, if possible. */
hfinfo = stnode_data(TOKEN);
dfilter_fail("Syntax error near \"%s\".", hfinfo->abbrev);
break;
+ case STTYPE_FUNCTION:
+ dfilter_fail("The function s was unexpected in this context.");
+ break;
/* These aren't handed to use as terminal tokens from
the scanner, so was can assert that we'll never
@@ -120,11 +127,6 @@ sentence ::= . { dfw->st_root = NULL; }
expr(X) ::= relation_test(R). { X = R; }
expr(X) ::= logical_test(L). { X = L; }
-expr(X) ::= LPAREN expr(Y) RPAREN.
-{
- X = Y;
-}
-
/* Logical tests */
logical_test(T) ::= expr(E) TEST_AND expr(F).
@@ -254,4 +256,35 @@ rel_op2(O) ::= TEST_CONTAINS. { O = TEST_OP_CONTAINS; }
rel_op2(O) ::= TEST_MATCHES. { O = TEST_OP_MATCHES; }
+/* Functions */
+
+/* A function can have one or more parameters */
+entity(E) ::= FUNCTION(F) LPAREN funcparams(P) RPAREN.
+{
+ E = F;
+ sttype_function_set_params(E, P);
+}
+
+/* A function can have zero parameters. */
+entity(E) ::= FUNCTION(F) LPAREN RPAREN.
+{
+ E = F;
+}
+
+funcparams(P) ::= entity(E).
+{
+ P = g_slist_append(NULL, E);
+}
+
+funcparams(P) ::= funcparams(L) COMMA entity(E).
+{
+ P = g_slist_append(L, E);
+}
+
+
+/* Any expression inside parens is simply that expression */
+expr(X) ::= LPAREN expr(Y) RPAREN.
+{
+ X = Y;
+}
diff --git a/epan/dfilter/scanner.l b/epan/dfilter/scanner.l
index a621292699..545c923c85 100644
--- a/epan/dfilter/scanner.l
+++ b/epan/dfilter/scanner.l
@@ -32,6 +32,7 @@
#include "dfilter-int.h"
#include "syntax-tree.h"
#include "grammar.h"
+#include "dfunctions.h"
/*
* GLib 1.2[.x] doesn't define G_MAXINT32 or G_MININT32; if they're not
@@ -75,6 +76,7 @@ GString* quoted_string = NULL;
"(" return simple(TOKEN_LPAREN);
")" return simple(TOKEN_RPAREN);
+"," return simple(TOKEN_COMMA);
"==" return simple(TOKEN_TEST_EQ);
"eq" return simple(TOKEN_TEST_EQ);
@@ -232,9 +234,10 @@ GString* quoted_string = NULL;
return set_lval(TOKEN_UNPARSED, yytext);
}
-[-\+[:alnum:]_.,:]+ {
+[-\+[:alnum:]_.:]+ {
/* Is it a field name? */
header_field_info *hfinfo;
+ df_func_def_t *df_func_def;
hfinfo = proto_registrar_get_byname(yytext);
if (hfinfo) {
@@ -242,8 +245,16 @@ GString* quoted_string = NULL;
return set_lval(TOKEN_FIELD, hfinfo);
}
else {
- /* No, so treat it as an unparsed string */
- return set_lval(TOKEN_UNPARSED, yytext);
+ /* Is it a function name? */
+ df_func_def = df_func_lookup(yytext);
+ if (df_func_def) {
+ /* yes, it's a dfilter function */
+ return set_lval(TOKEN_FUNCTION, df_func_def);
+ }
+ else {
+ /* No, so treat it as an unparsed string */
+ return set_lval(TOKEN_UNPARSED, yytext);
+ }
}
}
@@ -300,10 +311,12 @@ set_lval(int token, gpointer data)
case TOKEN_UNPARSED:
type_id = STTYPE_UNPARSED;
break;
+ case TOKEN_FUNCTION:
+ type_id = STTYPE_FUNCTION;
+ break;
default:
g_assert_not_reached();
}
-
stnode_init(df_lval, type_id, data);
return token;
}
diff --git a/epan/dfilter/semcheck.c b/epan/dfilter/semcheck.c
index b575be7a96..9e91bff0e5 100644
--- a/epan/dfilter/semcheck.c
+++ b/epan/dfilter/semcheck.c
@@ -31,6 +31,7 @@
#include "syntax-tree.h"
#include "sttype-range.h"
#include "sttype-test.h"
+#include "sttype-function.h"
#include <epan/exceptions.h>
#include <epan/packet.h>
@@ -307,6 +308,13 @@ check_exists(stnode_t *st_arg1)
THROW(TypeError);
break;
+ case STTYPE_FUNCTION:
+ /* XXX - Maybe we should change functions so they can return fields,
+ * in which case the 'exist' should be fine. */
+ dfilter_fail("You cannot test whether a function is present.");
+ THROW(TypeError);
+ break;
+
case STTYPE_UNINITIALIZED:
case STTYPE_TEST:
case STTYPE_INTEGER:
@@ -751,6 +759,161 @@ check_relation_LHS_RANGE(const char *relation_string, FtypeCanFunc can_func _U_,
}
}
+static stnode_t*
+check_param_entity(stnode_t *st_node)
+{
+ sttype_id_t e_type;
+ stnode_t *new_st;
+ fvalue_t *fvalue;
+ char *s;
+
+ e_type = stnode_type_id(st_node);
+ /* If there's an unparsed string, change it to an FT_STRING */
+ if (e_type == STTYPE_UNPARSED) {
+ s = stnode_data(st_node);
+ fvalue = fvalue_from_unparsed(FT_STRING, s, FALSE, dfilter_fail);
+ if (!fvalue) {
+ THROW(TypeError);
+ }
+
+ new_st = stnode_new(STTYPE_FVALUE, fvalue);
+ stnode_free(st_node);
+ return new_st;
+ }
+
+ return st_node;
+}
+
+
+/* If the LHS of a relation test is a FUNCTION, run some checks
+ * and possibly some modifications of syntax tree nodes. */
+static void
+check_relation_LHS_FUNCTION(const char *relation_string, FtypeCanFunc can_func,
+ gboolean allow_partial_value,
+ stnode_t *st_node, stnode_t *st_arg1, stnode_t *st_arg2)
+{
+ stnode_t *new_st;
+ sttype_id_t type2;
+ header_field_info *hfinfo2;
+ ftenum_t ftype1, ftype2;
+ fvalue_t *fvalue;
+ char *s;
+ int param_i;
+ drange_node *rn;
+ df_func_def_t *funcdef;
+ guint num_params;
+ GSList *params;
+
+ type2 = stnode_type_id(st_arg2);
+
+ funcdef = sttype_function_funcdef(st_arg1);
+ ftype1 = funcdef->retval_ftype;
+
+ params = sttype_function_params(st_arg1);
+ num_params = g_slist_length(params);
+ if (num_params < funcdef->min_nargs) {
+ dfilter_fail("Function %s needs at least %u arguments.",
+ funcdef->name, funcdef->min_nargs);
+ THROW(TypeError);
+ }
+ else if (num_params > funcdef->max_nargs) {
+ dfilter_fail("Function %s can only accept %u arguments.",
+ funcdef->name, funcdef->max_nargs);
+ THROW(TypeError);
+ }
+
+ param_i = 0;
+ while (params) {
+ params->data = check_param_entity(params->data);
+ funcdef->semcheck_param_function(param_i, params->data);
+ params = params->next;
+ }
+
+ DebugLog((" 5 check_relation_LHS_FUNCTION(%s)\n", relation_string));
+
+ if (!can_func(ftype1)) {
+ dfilter_fail("Function %s (type=%s) cannot participate in '%s' comparison.",
+ funcdef->name, ftype_pretty_name(ftype1),
+ relation_string);
+ THROW(TypeError);
+ }
+
+ if (type2 == STTYPE_FIELD) {
+ hfinfo2 = stnode_data(st_arg2);
+ ftype2 = hfinfo2->type;
+
+ if (!compatible_ftypes(ftype1, ftype2)) {
+ dfilter_fail("Function %s and %s are not of compatible types.",
+ funcdef->name, hfinfo2->abbrev);
+ THROW(TypeError);
+ }
+ /* Do this check even though you'd think that if
+ * they're compatible, then can_func() would pass. */
+ if (!can_func(ftype2)) {
+ dfilter_fail("%s (type=%s) cannot participate in specified comparison.",
+ hfinfo2->abbrev, ftype_pretty_name(ftype2));
+ THROW(TypeError);
+ }
+ }
+ else if (type2 == STTYPE_STRING) {
+ s = stnode_data(st_arg2);
+ if (strcmp(relation_string, "matches") == 0) {
+ /* Convert to a FT_PCRE */
+ fvalue = fvalue_from_string(FT_PCRE, s, dfilter_fail);
+ } else {
+ fvalue = fvalue_from_string(ftype1, s, dfilter_fail);
+ }
+ if (!fvalue) {
+ THROW(TypeError);
+ }
+
+ new_st = stnode_new(STTYPE_FVALUE, fvalue);
+ sttype_test_set2_args(st_node, st_arg1, new_st);
+ stnode_free(st_arg2);
+ }
+ else if (type2 == STTYPE_UNPARSED) {
+ s = stnode_data(st_arg2);
+ if (strcmp(relation_string, "matches") == 0) {
+ /* Convert to a FT_PCRE */
+ fvalue = fvalue_from_unparsed(FT_PCRE, s, FALSE, dfilter_fail);
+ } else {
+ fvalue = fvalue_from_unparsed(ftype1, s, allow_partial_value, dfilter_fail);
+ }
+ if (!fvalue) {
+ THROW(TypeError);
+ }
+
+ new_st = stnode_new(STTYPE_FVALUE, fvalue);
+ sttype_test_set2_args(st_node, st_arg1, new_st);
+ stnode_free(st_arg2);
+ }
+ else if (type2 == STTYPE_RANGE) {
+ check_drange_sanity(st_arg2);
+ if (!is_bytes_type(ftype1)) {
+ if (!ftype_can_slice(ftype1)) {
+ dfilter_fail("Function \"%s\" is a %s and cannot be converted into a sequence of bytes.",
+ funcdef->name,
+ ftype_pretty_name(ftype1));
+ THROW(TypeError);
+ }
+
+ /* Convert entire field to bytes */
+ new_st = stnode_new(STTYPE_RANGE, NULL);
+
+ rn = drange_node_new();
+ drange_node_set_start_offset(rn, 0);
+ drange_node_set_to_the_end(rn);
+ /* st_arg1 is freed in this step */
+ sttype_range_set1(new_st, st_arg1, rn);
+
+ sttype_test_set2_args(st_node, new_st, st_arg2);
+ }
+ }
+ else {
+ g_assert_not_reached();
+ }
+}
+
/* Check the semantics of any relational test. */
static void
@@ -795,12 +958,16 @@ header_field_info *hfinfo;
check_relation_LHS_UNPARSED(relation_string, can_func,
allow_partial_value, st_node, st_arg1, st_arg2);
break;
+ case STTYPE_FUNCTION:
+ check_relation_LHS_FUNCTION(relation_string, can_func,
+ allow_partial_value, st_node, st_arg1, st_arg2);
+ break;
case STTYPE_UNINITIALIZED:
case STTYPE_TEST:
case STTYPE_INTEGER:
case STTYPE_FVALUE:
- case STTYPE_NUM_TYPES:
+ default:
g_assert_not_reached();
}
}
diff --git a/epan/dfilter/sttype-function.c b/epan/dfilter/sttype-function.c
new file mode 100644
index 0000000000..c6c8a5af83
--- /dev/null
+++ b/epan/dfilter/sttype-function.c
@@ -0,0 +1,125 @@
+/*
+ * $Id$
+ *
+ * Copyright (c) 2006 by Gilbert Ramirez <gram@alumni.rice.edu>
+ *
+ * Ethereal - Network traffic analyzer
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "syntax-tree.h"
+#include "sttype-function.h"
+
+typedef struct {
+ guint32 magic;
+ df_func_def_t *funcdef;
+ GSList *params;
+} function_t;
+
+#define FUNCTION_MAGIC 0xe10f0f99
+
+static gpointer
+function_new(gpointer funcdef)
+{
+ function_t *stfuncrec;
+
+ g_assert(funcdef != NULL);
+
+ stfuncrec = g_new(function_t, 1);
+
+ stfuncrec->magic = FUNCTION_MAGIC;
+ stfuncrec->funcdef = funcdef;
+ stfuncrec->params = NULL;
+
+ return (gpointer) stfuncrec;
+}
+
+static void
+slist_stnode_free(gpointer data, gpointer user_data _U_)
+{
+ stnode_free(data);
+}
+
+void
+st_funcparams_free(GSList *params)
+{
+ g_slist_foreach(params, slist_stnode_free, NULL);
+ g_slist_free(params);
+}
+
+static void
+function_free(gpointer value)
+{
+ function_t *stfuncrec = value;
+ assert_magic(stfuncrec, FUNCTION_MAGIC);
+ st_funcparams_free(stfuncrec->params);
+ g_free(stfuncrec);
+}
+
+
+/* Set the parameters for a function stnode_t. */
+void
+sttype_function_set_params(stnode_t *node, GSList *params)
+{
+
+ function_t *stfuncrec;
+
+ stfuncrec = stnode_data(node);
+ assert_magic(stfuncrec, FUNCTION_MAGIC);
+
+ stfuncrec->params = params;
+}
+
+/* Get the function-definition record for a function stnode_t. */
+df_func_def_t*
+sttype_function_funcdef(stnode_t *node)
+{
+ function_t *stfuncrec;
+
+ stfuncrec = stnode_data(node);
+ assert_magic(stfuncrec, FUNCTION_MAGIC);
+ return stfuncrec->funcdef;
+}
+
+/* Get the parameters for a function stnode_t. */
+GSList*
+sttype_function_params(stnode_t *node)
+{
+ function_t *stfuncrec;
+
+ stfuncrec = stnode_data(node);
+ assert_magic(stfuncrec, FUNCTION_MAGIC);
+ return stfuncrec->params;
+}
+
+
+void
+sttype_register_function(void)
+{
+ static sttype_t function_type = {
+ STTYPE_FUNCTION,
+ "FUNCTION",
+ function_new,
+ function_free,
+ };
+
+ sttype_register(&function_type);
+}
+
diff --git a/epan/dfilter/sttype-function.h b/epan/dfilter/sttype-function.h
new file mode 100644
index 0000000000..b93f2e3273
--- /dev/null
+++ b/epan/dfilter/sttype-function.h
@@ -0,0 +1,42 @@
+/*
+ * $Id: sttype-test.h 11400 2004-07-18 00:24:25Z guy $
+ *
+ * Ethereal - Network traffic analyzer
+ * By Gerald Combs <gerald@zing.org>
+ * Copyright 2001 Gerald Combs
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef STTYPE_FUNCTION_H
+#define STTYPE_FUNCTION_H
+
+#include "dfunctions.h"
+
+/* Set the parameters for a function stnode_t. */
+void
+sttype_function_set_params(stnode_t *node, GSList *params);
+
+/* Get the function-definition record for a function stnode_t. */
+df_func_def_t* sttype_function_funcdef(stnode_t *node);
+
+/* Get the parameters for a function stnode_t. */
+GSList* sttype_function_params(stnode_t *node);
+
+/* Free the memory of a param list */
+void st_funcparams_free(GSList *params);
+
+#endif
diff --git a/epan/dfilter/syntax-tree.c b/epan/dfilter/syntax-tree.c
index 2fef146adf..62b54d97fe 100644
--- a/epan/dfilter/syntax-tree.c
+++ b/epan/dfilter/syntax-tree.c
@@ -36,6 +36,7 @@ static sttype_t* type_list[STTYPE_NUM_TYPES];
void
sttype_init(void)
{
+ sttype_register_function();
sttype_register_integer();
sttype_register_pointer();
sttype_register_range();
diff --git a/epan/dfilter/syntax-tree.h b/epan/dfilter/syntax-tree.h
index 5fd5dbbe14..d57c850f90 100644
--- a/epan/dfilter/syntax-tree.h
+++ b/epan/dfilter/syntax-tree.h
@@ -35,6 +35,7 @@ typedef enum {
STTYPE_FVALUE,
STTYPE_INTEGER,
STTYPE_RANGE,
+ STTYPE_FUNCTION,
STTYPE_NUM_TYPES
} sttype_id_t;
@@ -62,6 +63,7 @@ typedef struct {
} stnode_t;
/* These are the sttype_t registration function prototypes. */
+void sttype_register_function(void);
void sttype_register_integer(void);
void sttype_register_pointer(void);
void sttype_register_range(void);
diff --git a/epan/ftypes/ftype-bytes.c b/epan/ftypes/ftype-bytes.c
index 6de2616359..d67883cd53 100644
--- a/epan/ftypes/ftype-bytes.c
+++ b/epan/ftypes/ftype-bytes.c
@@ -480,6 +480,7 @@ ftype_register_bytes(void)
{
static ftype_t bytes_type = {
+ FT_BYTES, /* ftype */
"FT_BYTES", /* name */
"sequence of bytes", /* pretty_name */
0, /* wire_size */
@@ -515,6 +516,7 @@ ftype_register_bytes(void)
};
static ftype_t uint_bytes_type = {
+ FT_UINT_BYTES, /* ftype */
"FT_UINT_BYTES", /* name */
"sequence of bytes", /* pretty_name */
0, /* wire_size */
@@ -550,6 +552,7 @@ ftype_register_bytes(void)
};
static ftype_t ether_type = {
+ FT_ETHER, /* ftype */
"FT_ETHER", /* name */
"Ethernet or other MAC address",/* pretty_name */
ETHER_LEN, /* wire_size */
@@ -585,6 +588,7 @@ ftype_register_bytes(void)
};
static ftype_t ipv6_type = {
+ FT_IPv6, /* ftype */
"FT_IPv6", /* name */
"IPv6 address", /* pretty_name */
IPv6_LEN, /* wire_size */
@@ -620,6 +624,7 @@ ftype_register_bytes(void)
};
static ftype_t oid_type = {
+ FT_OID, /* ftype */
"OID", /* name */
"OBJECT IDENTIFIER", /* pretty_name */
0, /* wire_size */
diff --git a/epan/ftypes/ftype-double.c b/epan/ftypes/ftype-double.c
index af45990cdc..460b4c5b13 100644
--- a/epan/ftypes/ftype-double.c
+++ b/epan/ftypes/ftype-double.c
@@ -157,6 +157,7 @@ ftype_register_double(void)
{
static ftype_t float_type = {
+ FT_FLOAT, /* ftype */
"FT_FLOAT", /* name */
"floating point (single-precision)", /* pretty_name */
0, /* wire_size */
@@ -192,6 +193,7 @@ ftype_register_double(void)
};
static ftype_t double_type = {
+ FT_DOUBLE, /* ftype */
"FT_DOUBLE", /* name */
"floating point (double-precision)", /* pretty_name */
0, /* wire_size */
diff --git a/epan/ftypes/ftype-guid.c b/epan/ftypes/ftype-guid.c
index 08104453c8..4a5e9645d5 100644
--- a/epan/ftypes/ftype-guid.c
+++ b/epan/ftypes/ftype-guid.c
@@ -129,6 +129,7 @@ ftype_register_guid(void)
{
static ftype_t guid_type = {
+ FT_GUID, /* ftype */
"GUID", /* name */
"Globally Unique Identifier", /* pretty_name */
GUID_LEN, /* wire_size */
diff --git a/epan/ftypes/ftype-integer.c b/epan/ftypes/ftype-integer.c
index dc2954bb9f..9656facbbf 100644
--- a/epan/ftypes/ftype-integer.c
+++ b/epan/ftypes/ftype-integer.c
@@ -444,6 +444,7 @@ ftype_register_integers(void)
{
static ftype_t uint8_type = {
+ FT_UINT8, /* ftype */
"FT_UINT8", /* name */
"unsigned, 1 byte", /* pretty name */
1, /* wire_size */
@@ -478,6 +479,7 @@ ftype_register_integers(void)
NULL, /* slice */
};
static ftype_t uint16_type = {
+ FT_UINT16, /* ftype */
"FT_UINT16", /* name */
"unsigned, 2 bytes", /* pretty_name */
2, /* wire_size */
@@ -512,6 +514,7 @@ ftype_register_integers(void)
NULL, /* slice */
};
static ftype_t uint24_type = {
+ FT_UINT24, /* ftype */
"FT_UINT24", /* name */
"unsigned, 3 bytes", /* pretty_name */
3, /* wire_size */
@@ -546,6 +549,7 @@ ftype_register_integers(void)
NULL, /* slice */
};
static ftype_t uint32_type = {
+ FT_UINT32, /* ftype */
"FT_UINT32", /* name */
"unsigned, 4 bytes", /* pretty_name */
4, /* wire_size */
@@ -580,6 +584,7 @@ ftype_register_integers(void)
NULL, /* slice */
};
static ftype_t uint64_type = {
+ FT_UINT64, /* ftype */
"FT_UINT64", /* name */
"unsigned, 8 bytes", /* pretty_name */
8, /* wire_size */
@@ -614,6 +619,7 @@ ftype_register_integers(void)
NULL,
};
static ftype_t int8_type = {
+ FT_INT8, /* ftype */
"FT_INT8", /* name */
"signed, 1 byte", /* pretty_name */
1, /* wire_size */
@@ -648,6 +654,7 @@ ftype_register_integers(void)
NULL, /* slice */
};
static ftype_t int16_type = {
+ FT_INT16, /* ftype */
"FT_INT16", /* name */
"signed, 2 bytes", /* pretty_name */
2, /* wire_size */
@@ -682,6 +689,7 @@ ftype_register_integers(void)
NULL, /* slice */
};
static ftype_t int24_type = {
+ FT_INT24, /* ftype */
"FT_INT24", /* name */
"signed, 3 bytes", /* pretty_name */
3, /* wire_size */
@@ -716,6 +724,7 @@ ftype_register_integers(void)
NULL, /* slice */
};
static ftype_t int32_type = {
+ FT_INT32, /* ftype */
"FT_INT32", /* name */
"signed, 4 bytes", /* pretty_name */
4, /* wire_size */
@@ -750,6 +759,7 @@ ftype_register_integers(void)
NULL, /* slice */
};
static ftype_t int64_type = {
+ FT_INT64, /* ftype */
"FT_INT64", /* name */
"signed, 8 bytes", /* pretty_name */
8, /* wire_size */
@@ -784,6 +794,7 @@ ftype_register_integers(void)
NULL,
};
static ftype_t boolean_type = {
+ FT_BOOLEAN, /* ftype */
"FT_BOOLEAN", /* name */
"Boolean", /* pretty_name */
0, /* wire_size */
@@ -819,6 +830,7 @@ ftype_register_integers(void)
};
static ftype_t ipxnet_type = {
+ FT_IPXNET, /* ftype */
"FT_IPXNET", /* name */
"IPX network number", /* pretty_name */
4, /* wire_size */
@@ -854,6 +866,7 @@ ftype_register_integers(void)
};
static ftype_t framenum_type = {
+ FT_FRAMENUM, /* ftype */
"FT_FRAMENUM", /* name */
"frame number", /* pretty_name */
4, /* wire_size */
diff --git a/epan/ftypes/ftype-ipv4.c b/epan/ftypes/ftype-ipv4.c
index 65b8961dc8..d57894325c 100644
--- a/epan/ftypes/ftype-ipv4.c
+++ b/epan/ftypes/ftype-ipv4.c
@@ -199,6 +199,7 @@ ftype_register_ipv4(void)
{
static ftype_t ipv4_type = {
+ FT_IPv4, /* ftype */
"FT_IPv4", /* name */
"IPv4 address", /* pretty_name */
4, /* wire_size */
diff --git a/epan/ftypes/ftype-none.c b/epan/ftypes/ftype-none.c
index 4eb037eed9..471e0a4d23 100644
--- a/epan/ftypes/ftype-none.c
+++ b/epan/ftypes/ftype-none.c
@@ -32,6 +32,7 @@ ftype_register_none(void)
{
static ftype_t none_type = {
+ FT_NONE, /* ftype */
"FT_NONE", /* name */
"label", /* pretty_name */
0, /* wire_size */
diff --git a/epan/ftypes/ftype-pcre.c b/epan/ftypes/ftype-pcre.c
index 05db17e28a..82bcc196de 100644
--- a/epan/ftypes/ftype-pcre.c
+++ b/epan/ftypes/ftype-pcre.c
@@ -177,6 +177,7 @@ void
ftype_register_pcre(void)
{
static ftype_t pcre_type = {
+ FT_PCRE, /* ftype */
"FT_PCRE", /* name */
"Compiled Perl-Compatible Regular Expression object", /* pretty_name */
0, /* wire_size */
@@ -219,6 +220,7 @@ void
ftype_register_pcre(void)
{
static ftype_t pcre_type = {
+ FT_PCRE, /* ftype */
"FT_PCRE", /* name */
"Compiled Perl-Compatible Regular Expression object", /* pretty_name */
0, /* wire_size */
diff --git a/epan/ftypes/ftype-string.c b/epan/ftypes/ftype-string.c
index 70649b77b8..d4525fc279 100644
--- a/epan/ftypes/ftype-string.c
+++ b/epan/ftypes/ftype-string.c
@@ -301,6 +301,7 @@ ftype_register_string(void)
{
static ftype_t string_type = {
+ FT_STRING, /* ftype */
"FT_STRING", /* name */
"character string", /* pretty_name */
0, /* wire_size */
@@ -335,6 +336,7 @@ ftype_register_string(void)
slice,
};
static ftype_t stringz_type = {
+ FT_STRINGZ, /* ftype */
"FT_STRINGZ", /* name */
"character string", /* pretty name */
0, /* wire_size */
@@ -369,6 +371,7 @@ ftype_register_string(void)
slice,
};
static ftype_t uint_string_type = {
+ FT_UINT_STRING, /* ftype */
"FT_UINT_STRING", /* name */
"character string", /* pretty_name */
0, /* wire_size */
diff --git a/epan/ftypes/ftype-time.c b/epan/ftypes/ftype-time.c
index ed90960952..2427ccb5d5 100644
--- a/epan/ftypes/ftype-time.c
+++ b/epan/ftypes/ftype-time.c
@@ -345,6 +345,7 @@ ftype_register_time(void)
{
static ftype_t abstime_type = {
+ FT_ABSOLUTE_TIME, /* ftype */
"FT_ABSOLUTE_TIME", /* name */
"date/time", /* pretty_name */
0, /* wire_size */
@@ -379,6 +380,7 @@ ftype_register_time(void)
NULL
};
static ftype_t reltime_type = {
+ FT_RELATIVE_TIME, /* ftype */
"FT_RELATIVE_TIME", /* name */
"time offset", /* pretty_name */
0, /* wire_size */
diff --git a/epan/ftypes/ftype-tvbuff.c b/epan/ftypes/ftype-tvbuff.c
index f4c84b5d65..8e4a705059 100644
--- a/epan/ftypes/ftype-tvbuff.c
+++ b/epan/ftypes/ftype-tvbuff.c
@@ -260,6 +260,7 @@ ftype_register_tvbuff(void)
{
static ftype_t protocol_type = {
+ FT_PROTOCOL, /* ftype */
"FT_PROTOCOL", /* name */
"protocol", /* pretty_name */
0, /* wire_size */
diff --git a/epan/ftypes/ftypes.c b/epan/ftypes/ftypes.c
index e40dfc4f06..d48389496b 100644
--- a/epan/ftypes/ftypes.c
+++ b/epan/ftypes/ftypes.c
@@ -58,6 +58,7 @@ ftype_register(enum ftenum ftype, ftype_t *ft)
{
/* Check input */
g_assert(ftype < FT_NUM_TYPES);
+ g_assert(ftype == ft->ftype);
/* Don't re-register. */
g_assert(type_list[ftype] == NULL);
@@ -268,6 +269,12 @@ fvalue_from_string(ftenum_t ftype, char *s, LogFunc logfunc)
return NULL;
}
+ftype_t*
+fvalue_ftype(fvalue_t *fv)
+{
+ return fv->ftype;
+}
+
const char*
fvalue_type_name(fvalue_t *fv)
{
diff --git a/epan/ftypes/ftypes.h b/epan/ftypes/ftypes.h
index 6a30a4b7b5..a21feb5291 100644
--- a/epan/ftypes/ftypes.h
+++ b/epan/ftypes/ftypes.h
@@ -196,6 +196,7 @@ typedef guint (*FvalueLen)(fvalue_t*);
typedef void (*FvalueSlice)(fvalue_t*, GByteArray *, guint offset, guint length);
struct _ftype_t {
+ ftenum_t ftype;
const char *name;
const char *pretty_name;
int wire_size;
@@ -288,6 +289,9 @@ fvalue_string_repr_len(fvalue_t *fv, ftrepr_t rtype);
extern char *
fvalue_to_string_repr(fvalue_t *fv, ftrepr_t rtype, char *buf);
+ftype_t*
+fvalue_ftype(fvalue_t *fv);
+
const char*
fvalue_type_name(fvalue_t *fv);