aboutsummaryrefslogtreecommitdiffstats
path: root/epan
diff options
context:
space:
mode:
Diffstat (limited to 'epan')
-rw-r--r--epan/Makefile.am17
-rw-r--r--epan/configure.in8
-rw-r--r--epan/dfilter-grammar.y1191
-rw-r--r--epan/dfilter-int.h148
-rw-r--r--epan/dfilter-scanner.l366
-rw-r--r--epan/dfilter.c1086
-rw-r--r--epan/dfilter.h70
-rw-r--r--epan/dfilter/.cvsignore8
-rw-r--r--epan/dfilter/Makefile.am81
-rw-r--r--epan/dfilter/cppmagic.h14
-rw-r--r--epan/dfilter/dfilter-int.h52
-rw-r--r--epan/dfilter/dfilter.c352
-rw-r--r--epan/dfilter/dfilter.h65
-rw-r--r--epan/dfilter/dfvm.c395
-rw-r--r--epan/dfilter/dfvm.h77
-rw-r--r--epan/dfilter/gencode.c299
-rw-r--r--epan/dfilter/gencode.h7
-rw-r--r--epan/dfilter/glib-util.c47
-rw-r--r--epan/dfilter/glib-util.h4
-rw-r--r--epan/dfilter/grammar.lemon185
-rw-r--r--epan/dfilter/scanner.l157
-rw-r--r--epan/dfilter/semcheck.c472
-rw-r--r--epan/dfilter/semcheck.h10
-rw-r--r--epan/dfilter/sttype-pointer.c28
-rw-r--r--epan/dfilter/sttype-range.c174
-rw-r--r--epan/dfilter/sttype-range.h20
-rw-r--r--epan/dfilter/sttype-string.c29
-rw-r--r--epan/dfilter/sttype-test.c144
-rw-r--r--epan/dfilter/sttype-test.h30
-rw-r--r--epan/dfilter/syntax-tree.c169
-rw-r--r--epan/dfilter/syntax-tree.h95
-rw-r--r--epan/epan.c11
-rw-r--r--epan/epan.h7
-rw-r--r--epan/exceptions.h1
-rw-r--r--epan/ftypes/.cvsignore4
-rw-r--r--epan/ftypes/Makefile.am52
-rw-r--r--epan/ftypes/ftype-bytes.c386
-rw-r--r--epan/ftypes/ftype-double.c133
-rw-r--r--epan/ftypes/ftype-integer.c417
-rw-r--r--epan/ftypes/ftype-ipv4.c114
-rw-r--r--epan/ftypes/ftype-none.c20
-rw-r--r--epan/ftypes/ftype-string.c198
-rw-r--r--epan/ftypes/ftype-time.c78
-rw-r--r--epan/ftypes/ftype-tvbuff.c84
-rw-r--r--epan/ftypes/ftypes-int.h60
-rw-r--r--epan/ftypes/ftypes.c410
-rw-r--r--epan/ftypes/ftypes.h197
-rw-r--r--epan/gdebug.h38
-rw-r--r--epan/ipv4.h4
-rw-r--r--epan/proto.c532
-rw-r--r--epan/proto.h76
51 files changed, 5484 insertions, 3138 deletions
diff --git a/epan/Makefile.am b/epan/Makefile.am
index b7b716ac91..e3448e772d 100644
--- a/epan/Makefile.am
+++ b/epan/Makefile.am
@@ -2,7 +2,7 @@
# Automake file for the EPAN library
# (Ethereal Protocol ANalyzer Library)
#
-# $Id: Makefile.am,v 1.15 2001/01/17 06:13:39 guy Exp $
+# $Id: Makefile.am,v 1.16 2001/02/01 20:21:15 gram Exp $
#
# Ethereal - Network traffic analyzer
# By Gerald Combs <gerald@zing.org>
@@ -23,9 +23,7 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
-# Any POSIX-compatible YACC should honor the -p flag
-YFLAGS=-d -p dfilter_
+SUBDIRS = ftypes dfilter
# EPAN will eventually be a shared library. While I move source code around,
# however, it is an archive library.
@@ -41,11 +39,6 @@ libethereal_a_SOURCES = \
bitswap.h \
conversation.c \
conversation.h \
- dfilter-int.h \
- dfilter-grammar.y \
- dfilter-scanner.l \
- dfilter.c \
- dfilter.h \
epan.c \
epan.h \
except.c \
@@ -53,6 +46,7 @@ libethereal_a_SOURCES = \
exceptions.h \
filesystem.c \
filesystem.h \
+ gdebug.h \
ipv4.c \
ipv4.h \
packet.c \
@@ -78,9 +72,6 @@ EXTRA_libethereal_a_SOURCES = \
EXTRA_DIST = \
config.h.win32 \
- dfilter-grammar.c \
- dfilter-grammar.h \
- dfilter-scanner.c \
Makefile.nmake \
tvbtest.c
@@ -94,8 +85,6 @@ CLEANFILES = \
libethereal_a_LIBADD = @INET_ATON_O@ @INET_PTON_O@ @INET_NTOP_O@
libethereal_a_DEPENDENCIES = @INET_ATON_O@ @INET_PTON_O@ @INET_NTOP_O@
-dfilter-scanner.c : dfilter-scanner.l
- $(LEX) -Pdfilter_ -odfilter-scanner.c $(srcdir)/dfilter-scanner.l
tvbtest: tvbtest.o tvbuff.o except.o strutil.o
$(LINK) -o tvbtest tvbtest.o tvbuff.o except.o strutil.o `glib-config --libs`
diff --git a/epan/configure.in b/epan/configure.in
index b16734acce..51f84b489b 100644
--- a/epan/configure.in
+++ b/epan/configure.in
@@ -1,4 +1,4 @@
-# $Id: configure.in,v 1.3 2001/01/12 04:18:49 gram Exp $
+# $Id: configure.in,v 1.4 2001/02/01 20:21:15 gram Exp $
dnl
dnl Process this file with autoconf 2.13 or later to produce a
dnl configure script; 2.12 doesn't generate a "configure" script that
@@ -143,4 +143,8 @@ fi
AC_SUBST(INET_NTOP_C)
AC_SUBST(INET_NTOP_O)
-AC_OUTPUT(Makefile)
+AC_OUTPUT(
+ Makefile
+ dfilter/Makefile
+ ftypes/Makefile
+)
diff --git a/epan/dfilter-grammar.y b/epan/dfilter-grammar.y
deleted file mode 100644
index 757798c8ec..0000000000
--- a/epan/dfilter-grammar.y
+++ /dev/null
@@ -1,1191 +0,0 @@
-%{
-/* dfilter-grammar.y
- * Parser for display filters
- *
- * $Id: dfilter-grammar.y,v 1.2 2000/12/22 12:05:36 gram Exp $
- *
- * Ethereal - Network traffic analyzer
- * By Gerald Combs <gerald@zing.org>
- * Copyright 1998 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.
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#ifdef HAVE_SYS_TYPES_H
-# include <sys/types.h>
-#endif
-
-#ifdef HAVE_NETINET_IN_H
-# include <netinet/in.h>
-#endif
-
-#ifdef NEED_SNPRINTF_H
-# ifdef HAVE_STDARG_H
-# include <stdarg.h>
-# else
-# include <varargs.h>
-# endif
-# include "snprintf.h"
-#endif
-
-#ifndef __GLIB_H__
-#include <glib.h>
-#endif
-
-#include <string.h>
-#include <errno.h>
-#include <math.h>
-
-#ifndef _STDLIB_H
-#include <stdlib.h>
-#endif
-
-#ifndef __PROTO_H__
-#include "proto.h"
-#endif
-
-#ifndef __PACKET_H__
-#include "packet.h"
-#endif
-
-#ifndef __DFILTER_H__
-#include "dfilter.h"
-#endif
-
-#include "dfilter-int.h"
-
-#ifndef __RESOLV_H__
-#include "resolv.h"
-#endif
-
-static GNode* dfilter_mknode_join(GNode *n1, enum node_type ntype, int operand, GNode *n2);
-static GNode* dfilter_mknode_unary(int operand, GNode *n2);
-static GNode* dfilter_mknode_numeric_variable(gint id);
-static GNode* dfilter_mknode_numeric_value(guint32 val);
-static GNode* dfilter_mknode_floating_variable(gint id);
-static GNode* dfilter_mknode_floating_value(double val);
-static GNode* dfilter_mknode_ether_value(gchar*);
-static GNode* dfilter_mknode_ether_variable(gint id);
-static GNode* dfilter_mknode_ipxnet_value(guint32);
-static GNode* dfilter_mknode_ipxnet_variable(gint id);
-static GNode* dfilter_mknode_ipv4_value(char *host, int nmask_bits);
-static GNode* dfilter_mknode_ipv4_variable(gint id);
-static GNode* dfilter_mknode_ipv6_value(char *host);
-static GNode* dfilter_mknode_ipv6_variable(gint id);
-static GNode* dfilter_mknode_existence(gint id);
-static GNode* dfilter_mknode_bytes_value(GByteArray *barray);
-static GNode* dfilter_mknode_bytes_variable(gint id, gint offset, guint length, gboolean to_the_end);
-static GNode* dfilter_mknode_string_value(char *s);
-static GNode* dfilter_mknode_string_variable(gint id);
-
-static guint32 string_to_guint32(char *s, gboolean *success);
-static double string_to_double(char *s, gboolean *success);
-static int ether_str_to_guint8_array(const char *s, guint8 *mac);
-static guint dfilter_get_bytes_variable_offset(GNode *gnode);
-static guint dfilter_get_bytes_value_length(GNode* gnode);
-static void dfilter_set_bytes_variable_length(GNode *gnode, guint length);
-static guint dfilter_get_bytes_variable_length(GNode *gnode);
-static gint dfilter_get_bytes_variable_field_registered_length(GNode *gnode);
-static char* dfilter_get_variable_abbrev(GNode *gnode);
-static int check_bytes_variable_sanity(GNode *gnode);
-
-/* This is the dfilter we're currently processing. It's how
- * dfilter_compile communicates with us.
- */
-dfilter *global_df = NULL;
-
-%}
-
-%union {
- gint operand; /* logical, relation, alternation */
- struct {
- gint id;
- gint type; /* using macros defined below, in this yacc grammar */
- } variable;
- GNode* node;
- gchar* string;
- struct {
- gint offset;
- guint length;
- } byte_range;
-}
-
-%type <node> statement expression relation
-%type <node> numeric_value numeric_variable
-%type <node> floating_value floating_variable
-%type <node> ether_value ether_variable
-%type <node> ipxnet_value ipxnet_variable
-%type <node> ipv4_value ipv4_variable
-%type <node> ipv6_value ipv6_variable
-%type <node> string_value string_variable
-%type <node> variable_name
-%type <node> bytes_value bytes_variable
-
-%type <operand> numeric_relation
-%type <operand> equality_relation
-%type <operand> bytes_relation
-
-%type <variable> any_variable_type
-
-%token <variable> T_FT_UINT8
-%token <variable> T_FT_UINT16
-%token <variable> T_FT_UINT24
-%token <variable> T_FT_UINT32
-%token <variable> T_FT_INT8
-%token <variable> T_FT_INT16
-%token <variable> T_FT_INT24
-%token <variable> T_FT_INT32
-%token <variable> T_FT_ETHER
-%token <variable> T_FT_IPv4
-%token <variable> T_FT_IPv6
-%token <variable> T_FT_NONE
-%token <variable> T_FT_BYTES
-%token <variable> T_FT_BOOLEAN
-%token <variable> T_FT_STRING
-%token <variable> T_FT_IPXNET
-%token <variable> T_FT_DOUBLE
-
-%token <string> T_VAL_UNQUOTED_STRING
-%token <string> T_VAL_QUOTED_STRING
-%token <string> T_VAL_BYTE_STRING
-%token <byte_range> T_VAL_BYTE_RANGE
-
-%token <operand> TOK_AND TOK_OR TOK_NOT TOK_XOR
-%token <operand> TOK_EQ TOK_NE TOK_GT TOK_GE TOK_LT TOK_LE
-
-%expect 4
-%left TOK_AND
-%left TOK_OR TOK_XOR
-%nonassoc TOK_NOT
-
-%%
-
-statement: expression
- {
- global_df->dftree = $1;
- }
- | /* NULL */ { if (global_df != NULL) global_df->dftree = NULL; }
- ;
-
-expression: '(' expression ')' { $$ = $2; }
- | expression TOK_AND expression { $$ = dfilter_mknode_join($1, logical, $2, $3); }
- | expression TOK_OR expression { $$ = dfilter_mknode_join($1, logical, $2, $3); }
- | expression TOK_XOR expression { $$ = dfilter_mknode_join($1, logical, $2, $3); }
- | TOK_NOT expression { $$ = dfilter_mknode_unary(TOK_NOT, $2); }
- | relation { $$ = $1; }
- | variable_name { $$ = $1; }
- | expression error { YYABORT; }
- ;
-
-relation: numeric_variable numeric_relation numeric_value
- {
- $$ = dfilter_mknode_join($1, relation, $2, $3);
- }
- | numeric_variable numeric_relation numeric_variable
- {
- $$ = dfilter_mknode_join($1, relation, $2, $3);
- }
-
- | floating_variable numeric_relation floating_value
- {
- $$ = dfilter_mknode_join($1, relation, $2, $3);
- }
- | floating_variable numeric_relation floating_variable
- {
- $$ = dfilter_mknode_join($1, relation, $2, $3);
- }
-
- | ether_variable equality_relation ether_value
- {
- $$ = dfilter_mknode_join($1, relation, $2, $3);
- }
- | ether_variable equality_relation ether_variable
- {
- $$ = dfilter_mknode_join($1, relation, $2, $3);
- }
-
- | ipxnet_variable equality_relation ipxnet_value
- {
- $$ = dfilter_mknode_join($1, relation, $2, $3);
- }
- | ipxnet_variable equality_relation ipxnet_variable
- {
- $$ = dfilter_mknode_join($1, relation, $2, $3);
- }
-
- | string_variable equality_relation string_value
- {
- $$ = dfilter_mknode_join($1, relation, $2, $3);
- }
- | string_variable equality_relation string_variable
- {
- $$ = dfilter_mknode_join($1, relation, $2, $3);
- }
-
-
- | ipv4_variable numeric_relation ipv4_value
- {
- $$ = dfilter_mknode_join($1, relation, $2, $3);
- }
- | ipv4_variable numeric_relation ipv4_variable
- {
- $$ = dfilter_mknode_join($1, relation, $2, $3);
- }
-
- | ipv6_variable equality_relation ipv6_value
- {
- $$ = dfilter_mknode_join($1, relation, $2, $3);
- }
- | ipv6_variable equality_relation ipv6_variable
- {
- $$ = dfilter_mknode_join($1, relation, $2, $3);
- }
-
- | bytes_variable bytes_relation bytes_value
- {
- int a_len, b_len;
-
- a_len = dfilter_get_bytes_variable_length($1);
- b_len = dfilter_get_bytes_value_length($3);
-
- if (a_len == 0) {
- dfilter_set_bytes_variable_length($1, b_len);
- a_len = b_len;
- }
-
- if (!check_bytes_variable_sanity($1)) {
- YYERROR;
- }
-
- if (a_len != b_len) {
- dfilter_fail("Field \"%s\" has %u byte%s being compared, but %u byte%s "
- "%s supplied.",
- dfilter_get_variable_abbrev($1),
- a_len, plurality(a_len, "", "s"),
- b_len, plurality(b_len, "", "s"),
- plurality(b_len, "was", "were"));
- YYERROR;
- }
-
- $$ = dfilter_mknode_join($1, relation, $2, $3);
- }
- | bytes_variable bytes_relation bytes_variable
- {
- int a_len, b_len;
-
- a_len = dfilter_get_bytes_variable_length($1);
- b_len = dfilter_get_bytes_variable_length($3);
-
- if (!check_bytes_variable_sanity($1)) {
- YYERROR;
- }
-
- if (!check_bytes_variable_sanity($3)) {
- YYERROR;
- }
-
- if (a_len != b_len) {
- dfilter_fail("Fields \"%s\" and \"%s\" are being compared with "
- "disparate lengths of %u byte%s and %u byte%s.",
- dfilter_get_variable_abbrev($1),
- dfilter_get_variable_abbrev($3),
- a_len, plurality(a_len, "", "s"),
- b_len, plurality(b_len, "", "s"));
- YYERROR;
- }
-
- $$ = dfilter_mknode_join($1, relation, $2, $3);
- }
-
- ;
-
-
-numeric_value: T_VAL_UNQUOTED_STRING
- {
- gboolean success;
- $$ = dfilter_mknode_numeric_value(string_to_guint32($1, &success));
- g_free($1);
- if (!success) {
- YYERROR;
- }
- }
- ;
-
-ether_value: T_VAL_BYTE_STRING
- {
- $$ = dfilter_mknode_ether_value($1);
- g_free($1);
- if ($$ == NULL) {
- YYERROR;
- }
- }
- ;
-
-string_value: T_VAL_UNQUOTED_STRING
- {
- $$ = dfilter_mknode_string_value($1);
- g_free($1);
- if ($$ == NULL) {
- YYERROR;
- }
- }
- | T_VAL_QUOTED_STRING
- {
- $$ = dfilter_mknode_string_value($1);
- g_free($1);
- if ($$ == NULL) {
- YYERROR;
- }
- }
- ;
-
-ipxnet_value: T_VAL_UNQUOTED_STRING
- {
- gboolean success;
- $$ = dfilter_mknode_ipxnet_value(string_to_guint32($1, &success));
- g_free($1);
- if (!success) {
- YYERROR;
- }
- }
- ;
-
-floating_value: T_VAL_UNQUOTED_STRING
- {
- gboolean success;
- $$ = dfilter_mknode_floating_value(string_to_double($1, &success));
- g_free($1);
- if (!success) {
- YYERROR;
- }
- }
-
- | T_VAL_BYTE_STRING
- {
- /* e.g., 0.0, 0.1, 0.01 ... */
- gboolean success;
- $$ = dfilter_mknode_floating_value(string_to_double($1, &success));
- g_free($1);
- if (!success) {
- YYERROR;
- }
- }
- ;
-
-ipv4_value: T_VAL_UNQUOTED_STRING
- {
- $$ = dfilter_mknode_ipv4_value($1, 32);
- g_free($1);
- if ($$ == NULL) {
- YYERROR;
- }
- }
-
- | T_VAL_BYTE_STRING
- {
- $$ = dfilter_mknode_ipv4_value($1, 32);
- g_free($1);
- if ($$ == NULL) {
- YYERROR;
- }
- }
-
- | T_VAL_UNQUOTED_STRING '/' T_VAL_UNQUOTED_STRING
- {
- gboolean success;
- guint32 nmask_bits;
-
- nmask_bits = string_to_guint32($3, &success);
- if (!success) {
- g_free($1);
- g_free($3);
- YYERROR;
- }
-
- if (nmask_bits > 32) {
- dfilter_fail("The number of netmask bits in \"%s/%s\" should "
- "be between 0 and 32.", $1, $3);
- g_free($1);
- g_free($3);
- YYERROR;
- }
-
- $$ = dfilter_mknode_ipv4_value($1, nmask_bits);
- g_free($1);
- g_free($3);
- if ($$ == NULL) {
- YYERROR;
- }
- }
-
- | T_VAL_BYTE_STRING '/' T_VAL_UNQUOTED_STRING
- {
- gboolean success;
- guint32 nmask_bits;
-
- nmask_bits = string_to_guint32($3, &success);
- if (!success) {
- g_free($1);
- g_free($3);
- YYERROR;
- }
-
- if (nmask_bits > 32) {
- dfilter_fail("The number of netmask bits in \"%s/%s\" should "
- "be between 0 and 32.", $1, $3);
- g_free($1);
- g_free($3);
- YYERROR;
- }
- $$ = dfilter_mknode_ipv4_value($1, nmask_bits);
- g_free($1);
- g_free($3);
- if ($$ == NULL) {
- YYERROR;
- }
- }
- ;
-
-ipv6_value: T_VAL_UNQUOTED_STRING
- {
- $$ = dfilter_mknode_ipv6_value($1);
- g_free($1);
- if ($$ == NULL) {
- YYERROR;
- }
- }
-
- | T_VAL_BYTE_STRING
- {
- $$ = dfilter_mknode_ipv6_value($1);
- g_free($1);
- if ($$ == NULL) {
- YYERROR;
- }
- }
- ;
-
-bytes_value: T_VAL_BYTE_STRING
- {
- GByteArray *barray;
-
- /* the next function appends to list_of_byte_arrays for me */
- barray = byte_str_to_guint8_array($1);
- $$ = dfilter_mknode_bytes_value(barray);
- g_free($1);
- }
-
- | T_VAL_UNQUOTED_STRING
- {
- gboolean success;
- guint32 val32;
- guint8 val8;
- GByteArray *barray;
-
- val32 = string_to_guint32($1, &success);
- if (!success) {
- g_free($1);
- YYERROR;
- }
- if (val32 > 0xff) {
- dfilter_fail("The value \"%s\" cannot be stored in a single-byte byte-string. "
- "Use the multi-byte \"xx:yy\" representation.", $1);
- g_free($1);
- YYERROR;
- }
- val8 = (guint8) val32;
- barray = g_byte_array_new();
- global_df->list_of_byte_arrays = g_slist_append(global_df->list_of_byte_arrays, barray);
- g_byte_array_append(barray, &val8, 1);
-
- $$ = dfilter_mknode_bytes_value(barray);
- g_free($1);
- }
- ;
-
-numeric_variable: T_FT_UINT8 { $$ = dfilter_mknode_numeric_variable($1.id); }
- | T_FT_UINT16 { $$ = dfilter_mknode_numeric_variable($1.id); }
- | T_FT_UINT24 { $$ = dfilter_mknode_numeric_variable($1.id); }
- | T_FT_UINT32 { $$ = dfilter_mknode_numeric_variable($1.id); }
- | T_FT_INT8 { $$ = dfilter_mknode_numeric_variable($1.id); }
- | T_FT_INT16 { $$ = dfilter_mknode_numeric_variable($1.id); }
- | T_FT_INT24 { $$ = dfilter_mknode_numeric_variable($1.id); }
- | T_FT_INT32 { $$ = dfilter_mknode_numeric_variable($1.id); }
- ;
-
-ether_variable: T_FT_ETHER { $$ = dfilter_mknode_ether_variable($1.id); }
- ;
-
-floating_variable: T_FT_DOUBLE { $$ = dfilter_mknode_floating_variable($1.id); }
- ;
-
-ipxnet_variable: T_FT_IPXNET { $$ = dfilter_mknode_ipxnet_variable($1.id); }
- ;
-
-ipv4_variable: T_FT_IPv4 { $$ = dfilter_mknode_ipv4_variable($1.id); }
- ;
-
-ipv6_variable: T_FT_IPv6 { $$ = dfilter_mknode_ipv6_variable($1.id); }
- ;
-
-string_variable: T_FT_STRING { $$ = dfilter_mknode_string_variable($1.id); }
- ;
-
-bytes_variable: T_FT_BYTES T_VAL_BYTE_RANGE
- {
- $$ = dfilter_mknode_bytes_variable($1.id, $2.offset, $2.length, FALSE);
- }
-
- | T_FT_BYTES
- {
- $$ = dfilter_mknode_bytes_variable($1.id, 0, 0, TRUE);
- }
-
- ;
-
-variable_name: any_variable_type
- {
- GNode *variable;
- GNode *value;
- if ($1.type == T_FT_BOOLEAN) {
- /* Make "variable == TRUE" for BOOLEAN variable */
- variable = dfilter_mknode_numeric_variable($1.id);
- value = dfilter_mknode_numeric_value(TRUE);
- $$ = dfilter_mknode_join(variable, relation, TOK_EQ, value);
- }
- else {
- $$ = dfilter_mknode_existence($1.id);
- }
- }
- ;
-
-any_variable_type: T_FT_UINT8 { $$ = $1; }
- | T_FT_UINT16 { $$ = $1; }
- | T_FT_UINT24 { $$ = $1; }
- | T_FT_UINT32 { $$ = $1; }
- | T_FT_INT8 { $$ = $1; }
- | T_FT_INT16 { $$ = $1; }
- | T_FT_INT24 { $$ = $1; }
- | T_FT_INT32 { $$ = $1; }
- | T_FT_DOUBLE { $$ = $1; }
- | T_FT_ETHER { $$ = $1; }
- | T_FT_IPv4 { $$ = $1; }
- | T_FT_IPv6 { $$ = $1; }
- | T_FT_IPXNET { $$ = $1; }
- | T_FT_NONE { $$ = $1; }
- | T_FT_BYTES { $$ = $1; }
- | T_FT_BOOLEAN { $$ = $1; }
- | T_FT_STRING { $$ = $1; }
- ;
-
-numeric_relation: TOK_EQ { $$ = TOK_EQ; }
- | TOK_NE { $$ = TOK_NE; }
- | TOK_GT { $$ = TOK_GT; }
- | TOK_GE { $$ = TOK_GE; }
- | TOK_LT { $$ = TOK_LT; }
- | TOK_LE { $$ = TOK_LE; }
- ;
-
-equality_relation: TOK_EQ { $$ = TOK_EQ; }
- | TOK_NE { $$ = TOK_NE; }
- ;
-
-bytes_relation: TOK_EQ { $$ = TOK_EQ; }
- | TOK_NE { $$ = TOK_NE; }
- | TOK_GT { $$ = TOK_GT; }
- | TOK_LT { $$ = TOK_LT; }
- ;
-
-%%
-
-static GNode*
-dfilter_mknode_join(GNode *n1, enum node_type ntype, int operand, GNode *n2)
-{
- dfilter_node *node_root;
- GNode *gnode_root;
-
- node_root = g_mem_chunk_alloc(global_df->node_memchunk);
- node_root->ntype = ntype;
- node_root->elem_size = 0;
- node_root->fill_array_variable_func = NULL;
- node_root->fill_array_value_func = NULL;
- node_root->check_relation_func = NULL;
- if (ntype == relation) {
- node_root->value.relation = operand;
- }
- else if (ntype == logical) {
- node_root->value.logical = operand;
- }
- else {
- g_assert_not_reached();
- }
-
- gnode_root = g_node_new(node_root);
- g_node_append(gnode_root, n1);
- g_node_append(gnode_root, n2);
-
- return gnode_root;
-}
-
-static GNode*
-dfilter_mknode_unary(int operand, GNode *n2)
-{
- dfilter_node *node_root;
- GNode *gnode_root;
-
- node_root = g_mem_chunk_alloc(global_df->node_memchunk);
- node_root->ntype = logical;
- node_root->value.logical = operand;
- node_root->elem_size = 0;
- node_root->fill_array_variable_func = NULL;
- node_root->fill_array_value_func = NULL;
- node_root->check_relation_func = NULL;
-
- gnode_root = g_node_new(node_root);
- g_node_append(gnode_root, n2);
-
- return gnode_root;
-}
-
-
-static GNode*
-dfilter_mknode_numeric_variable(gint id)
-{
- dfilter_node *node;
- GNode *gnode;
-
- node = g_mem_chunk_alloc(global_df->node_memchunk);
- node->ntype = variable;
- node->elem_size = sizeof(guint32);
- node->fill_array_variable_func = fill_array_numeric_variable;
- node->fill_array_value_func = NULL;
- node->check_relation_func = check_relation_numeric;
- node->value.variable = id;
- gnode = g_node_new(node);
-
- return gnode;
-}
-
-static GNode*
-dfilter_mknode_ether_variable(gint id)
-{
- dfilter_node *node;
- GNode *gnode;
-
- node = g_mem_chunk_alloc(global_df->node_memchunk);
- node->ntype = variable;
- node->elem_size = sizeof(guint8) * 6;
- node->fill_array_variable_func = fill_array_ether_variable;
- node->fill_array_value_func = NULL;
- node->check_relation_func = check_relation_ether;
- node->value.variable = id;
- gnode = g_node_new(node);
-
- return gnode;
-}
-
-static GNode*
-dfilter_mknode_floating_variable(gint id)
-{
- dfilter_node *node;
- GNode *gnode;
-
- node = g_mem_chunk_alloc(global_df->node_memchunk);
- node->ntype = variable;
- node->elem_size = sizeof(double);
- node->fill_array_variable_func = fill_array_floating_variable;
- node->fill_array_value_func = NULL;
- node->check_relation_func = check_relation_floating;
- node->value.variable = id;
- gnode = g_node_new(node);
-
- return gnode;
-}
-
-static GNode*
-dfilter_mknode_ipxnet_variable(gint id)
-{
- dfilter_node *node;
- GNode *gnode;
-
- node = g_mem_chunk_alloc(global_df->node_memchunk);
- node->ntype = variable;
- node->elem_size = sizeof(guint8) * 4;
- node->fill_array_variable_func = fill_array_numeric_variable; /* cheating ! */
- node->fill_array_value_func = NULL;
- node->check_relation_func = check_relation_numeric; /* cheating ! */
- node->value.variable = id;
- gnode = g_node_new(node);
-
- return gnode;
-}
-
-static GNode*
-dfilter_mknode_ipv4_variable(gint id)
-{
- dfilter_node *node;
- GNode *gnode;
-
- node = g_mem_chunk_alloc(global_df->node_memchunk);
- node->ntype = variable;
- node->elem_size = sizeof(ipv4_addr);
- node->fill_array_variable_func = fill_array_ipv4_variable;
- node->fill_array_value_func = NULL;
- node->check_relation_func = check_relation_ipv4;
- node->value.variable = id;
- gnode = g_node_new(node);
-
- return gnode;
-}
-
-static GNode*
-dfilter_mknode_ipv6_variable(gint id)
-{
- dfilter_node *node;
- GNode *gnode;
-
- node = g_mem_chunk_alloc(global_df->node_memchunk);
- node->ntype = variable;
- node->elem_size = 16;
- node->fill_array_variable_func = fill_array_ipv6_variable;
- node->fill_array_value_func = NULL;
- node->check_relation_func = check_relation_ipv6;
- node->value.variable = id;
- gnode = g_node_new(node);
-
- return gnode;
-}
-
-static GNode*
-dfilter_mknode_string_variable(gint id)
-{
- dfilter_node *node;
- GNode *gnode;
-
- node = g_mem_chunk_alloc(global_df->node_memchunk);
- node->ntype = variable;
- node->elem_size = sizeof(char*);
- node->fill_array_variable_func = fill_array_string_variable;
- node->fill_array_value_func = NULL;
- node->check_relation_func = check_relation_string;
- node->value.variable = id;
- gnode = g_node_new(node);
-
- return gnode;
-}
-
-static GNode*
-dfilter_mknode_bytes_variable(gint id, gint offset, guint length, gboolean to_the_end)
-{
- dfilter_node *node;
- GNode *gnode;
-
- node = g_mem_chunk_alloc(global_df->node_memchunk);
- node->ntype = variable;
- node->elem_size = sizeof(GByteArray*);
- node->fill_array_variable_func = fill_array_bytes_variable;
- node->fill_array_value_func = NULL;
- node->check_relation_func = check_relation_bytes;
- node->value.variable = id;
- node->offset = offset;
- node->length = length;
- node->to_the_end = to_the_end;
- gnode = g_node_new(node);
-
- return gnode;
-}
-
-/* Gets length of variable represented by node from proto_register */
-static gint
-dfilter_get_bytes_variable_field_registered_length(GNode *gnode)
-{
- dfilter_node *node = gnode->data;
-
- /* Is this really a bytes_variable? */
- g_assert(node->fill_array_variable_func == fill_array_bytes_variable);
-
- return proto_registrar_get_length(node->value.variable);
-}
-
-/* Sets the length of a bytes_variable node */
-static void
-dfilter_set_bytes_variable_length(GNode *gnode, guint length)
-{
- dfilter_node *node = gnode->data;
-
- /* Is this really a bytes_variable? */
- g_assert(node->fill_array_variable_func == fill_array_bytes_variable);
-
- node->length = length;
-}
-
-/* Gets the length of a bytes_variable node */
-static guint
-dfilter_get_bytes_variable_length(GNode *gnode)
-{
- dfilter_node *node = gnode->data;
-
- /* Is this really a bytes_variable? */
- g_assert(node->fill_array_variable_func == fill_array_bytes_variable);
-
- return node->length;
-}
-
-/* Gets the offset of a bytes_variable node */
-static guint
-dfilter_get_bytes_variable_offset(GNode *gnode)
-{
- dfilter_node *node = gnode->data;
-
- /* Is this really a bytes_variable? */
- g_assert(node->fill_array_variable_func == fill_array_bytes_variable);
-
- return node->offset;
-}
-
-static char*
-dfilter_get_variable_abbrev(GNode *gnode)
-{
- dfilter_node *node = gnode->data;
-
- return proto_registrar_get_abbrev(node->value.variable);
-}
-
-static GNode*
-dfilter_mknode_numeric_value(guint32 val)
-{
- dfilter_node *node;
- GNode *gnode;
-
- node = g_mem_chunk_alloc(global_df->node_memchunk);
- node->ntype = numeric;
- node->elem_size = sizeof(guint32);
- node->fill_array_variable_func = NULL;
- node->fill_array_value_func = fill_array_numeric_value;
- node->check_relation_func = check_relation_numeric;
- node->value.numeric = val;
- gnode = g_node_new(node);
-
- return gnode;
-}
-
-static GNode*
-dfilter_mknode_floating_value(double val)
-{
- dfilter_node *node;
- GNode *gnode;
-
- node = g_mem_chunk_alloc(global_df->node_memchunk);
- node->ntype = floating;
- node->elem_size = sizeof(double);
- node->fill_array_variable_func = NULL;
- node->fill_array_value_func = fill_array_floating_value;
- node->check_relation_func = check_relation_floating;
- node->value.floating = val;
- gnode = g_node_new(node);
-
- return gnode;
-}
-
-/* Returns NULL on bad parse of ETHER value */
-static GNode*
-dfilter_mknode_ether_value(gchar *byte_string)
-{
- dfilter_node *node;
- GNode *gnode;
-
- node = g_mem_chunk_alloc(global_df->node_memchunk);
- node->ntype = ether;
- node->elem_size = sizeof(guint8) * 6;
- node->fill_array_variable_func = NULL;
- node->fill_array_value_func = fill_array_ether_value;
- node->check_relation_func = check_relation_ether;
-
- if (!ether_str_to_guint8_array(byte_string, &node->value.ether[0])) {
- /* Rather than free the mem_chunk allocation, let it
- * stay. It will be cleaned up when "dfilter_compile()"
- * calls "dfilter_destroy()". */
- dfilter_fail("\"%s\" is not a valid hardware address.",
- byte_string);
- return NULL;
- }
-
- gnode = g_node_new(node);
- return gnode;
-}
-
-static GNode*
-dfilter_mknode_ipxnet_value(guint32 ipx_net_val)
-{
- dfilter_node *node;
- GNode *gnode;
-
- node = g_mem_chunk_alloc(global_df->node_memchunk);
- node->ntype = ipxnet;
- node->elem_size = sizeof(guint8) * 4;
- node->fill_array_variable_func = NULL;
- node->fill_array_value_func = fill_array_numeric_value; /* cheating ! */
- node->check_relation_func = check_relation_numeric; /* cheating ! */
- node->value.numeric = ipx_net_val;
- gnode = g_node_new(node);
-
- return gnode;
-}
-
-/* Returns NULL on bad parse of IP value */
-static GNode*
-dfilter_mknode_ipv4_value(char *host, int nmask_bits)
-{
- dfilter_node *node;
- GNode *gnode;
- guint32 addr;
-
- node = g_mem_chunk_alloc(global_df->node_memchunk);
- node->ntype = numeric;
- node->elem_size = sizeof(ipv4_addr);
- node->fill_array_variable_func = NULL;
- node->fill_array_value_func = fill_array_ipv4_value;
- node->check_relation_func = check_relation_ipv4;
- if (!get_host_ipaddr(host, &addr)) {
- /* Rather than free the mem_chunk allocation, let it
- * stay. It will be cleaned up when "dfilter_compile()"
- * calls "dfilter_destroy()". */
- dfilter_fail("\"%s\" isn't a valid host name or IP address.",
- host);
- return NULL;
- }
- ipv4_addr_set_host_order_addr(&node->value.ipv4, addr);
- ipv4_addr_set_netmask_bits(&node->value.ipv4, nmask_bits);
-
- gnode = g_node_new(node);
- return gnode;
-}
-
-/* Returns NULL on bad parse of IPv6 value */
-static GNode*
-dfilter_mknode_ipv6_value(char *host)
-{
- dfilter_node *node;
- GNode *gnode;
-
- node = g_mem_chunk_alloc(global_df->node_memchunk);
- node->ntype = ipv6;
- node->elem_size = 16;
- node->fill_array_variable_func = NULL;
- node->fill_array_value_func = fill_array_ipv6_value;
- node->check_relation_func = check_relation_ipv6;
-
- if (!get_host_ipaddr6(host, (struct e_in6_addr*)&node->value.ipv6[0])) {
- /* Rather than free the mem_chunk allocation, let it
- * stay. It will be cleaned up when "dfilter_compile()"
- * calls "dfilter_destroy()". */
- dfilter_fail("\"%s\" isn't a valid IPv6 address.",
- host);
- return NULL;
- }
-
- gnode = g_node_new(node);
- return gnode;
-}
-
-
-static GNode*
-dfilter_mknode_string_value(char *s)
-{
- dfilter_node *node;
- GNode *gnode;
-
- node = g_mem_chunk_alloc(global_df->node_memchunk);
- node->ntype = string;
- node->elem_size = sizeof(char*);
- node->fill_array_variable_func = NULL;
- node->fill_array_value_func = fill_array_string_value;
- node->check_relation_func = check_relation_string;
- node->value.string = g_strdup(s);
- global_df->list_of_strings = g_slist_append(global_df->list_of_strings,
- node->value.string);
- gnode = g_node_new(node);
-
- return gnode;
-}
-
-
-static GNode*
-dfilter_mknode_bytes_value(GByteArray *barray)
-{
- dfilter_node *node;
- GNode *gnode;
-
- node = g_mem_chunk_alloc(global_df->node_memchunk);
- node->ntype = bytes;
- node->elem_size = sizeof(GByteArray*);
- node->fill_array_variable_func = NULL;
- node->fill_array_value_func = fill_array_bytes_value;
- node->check_relation_func = check_relation_bytes;
- node->value.bytes = barray;
- node->offset = G_MAXINT;
- node->length = barray->len;
- gnode = g_node_new(node);
-
- return gnode;
-}
-
-/* Given a node representing a bytes_value, returns
- * the length of the byte array */
-static guint
-dfilter_get_bytes_value_length(GNode* gnode)
-{
- dfilter_node *node = gnode->data;
-
- g_assert(node->ntype == bytes);
- return node->length;
-}
-
-static guint32
-string_to_guint32(char *s, gboolean *success)
-{
- char *endptr;
- guint32 val;
-
- val = strtoul(s, &endptr, 0);
- *success = TRUE;
- if (endptr == s || *endptr != '\0') {
- /* This isn't a valid number. */
- dfilter_fail("\"%s\" is not a valid number.", s);
- *success = FALSE;
- }
- if (errno == ERANGE) {
- *success = FALSE;
- if (val == ULONG_MAX) {
- dfilter_fail("\"%s\" causes an integer overflow.", s);
- }
- else {
- dfilter_fail("\"%s\" is not an integer.", s);
- }
- }
-
- return (guint32)val;
-}
-
-static double
-string_to_double(char *s, gboolean *success)
-{
- char *endptr = NULL;
- double retval;
-
- retval = strtod(s, &endptr);
- *success = TRUE;
-
- if (endptr == s) {
- dfilter_fail("\"%s\" is not a valid floating-point number.", s);
- *success = FALSE;
- }
-
- if (errno == ERANGE) {
- *success = FALSE;
- if (retval == 0) {
- dfilter_fail("\"%s\" causes a floating-point underflow.", s);
- }
- else if (retval == HUGE_VAL) {
- dfilter_fail("\"%s\" causes a floating-point overflow.", s);
- }
- else {
- dfilter_fail("\"%s\" is not a valid floating-point.", s);
- }
- }
- return retval;
-}
-
-static GNode*
-dfilter_mknode_existence(gint id)
-{
- dfilter_node *node;
- GNode *gnode;
-
- node = g_mem_chunk_alloc(global_df->node_memchunk);
- node->ntype = existence;
- node->elem_size = sizeof(guint32);
- node->fill_array_variable_func = NULL;
- node->fill_array_value_func = NULL;
- node->check_relation_func = NULL;
- node->value.variable = id;
- gnode = g_node_new(node);
-
- return gnode;
-}
-
-
-/* converts a string representing an ether HW address
- * to a guint8 array.
- *
- * Returns 0 on failure, 1 on success.
- */
-static int
-ether_str_to_guint8_array(const char *s, guint8 *mac)
-{
- char ether_str[18]; /* 2+1+2+1+2+1+2+1+2+1+2 + 1 */
- char *p, *str;
- int i = 0;
-
- if (strlen(s) > 17) {
- return 0;
- }
- strcpy(ether_str, s); /* local copy of string */
- str = ether_str;
- while ((p = strtok(str, "-:."))) {
- /* catch short strings with too many hex bytes: 0.0.0.0.0.0.0 */
- if (i > 5) {
- return 0;
- }
- mac[i] = (guint8) strtoul(p, NULL, 16);
- i++;
- /* subsequent calls to strtok() require NULL as arg 1 */
- str = NULL;
- }
- if (i != 6)
- return 0; /* failed to read 6 hex pairs */
- else
- return 1; /* read exactly 6 hex pairs */
-}
-
-
-static int
-check_bytes_variable_sanity(GNode *gnode)
-{
- int a_off, a_len, reg_len, t_off;
-
- a_off = dfilter_get_bytes_variable_offset(gnode);
- a_len = dfilter_get_bytes_variable_length(gnode);
- reg_len = dfilter_get_bytes_variable_field_registered_length(gnode);
-
- if (reg_len > 0) {
- t_off = a_off >= 0 ? a_off : reg_len + a_off;
- if (t_off + a_len > reg_len) {
- dfilter_fail("The \"%s\" field is only %u byte%s wide, but "
- "%u byte%s %s supplied.",
- dfilter_get_variable_abbrev(gnode),
- reg_len, plurality(reg_len, "", "s"),
- a_len, plurality(a_len, "", "s"),
- plurality(a_len, "was", "were"));
- return 0;
- }
- }
- return 1;
-}
diff --git a/epan/dfilter-int.h b/epan/dfilter-int.h
deleted file mode 100644
index c50462440d..0000000000
--- a/epan/dfilter-int.h
+++ /dev/null
@@ -1,148 +0,0 @@
-/* dfilter-int.h
- * Definitions for routines common to multiple modules in the display
- * filter code, but not used outside that code.
- *
- * $Id: dfilter-int.h,v 1.2 2000/12/22 12:05:36 gram Exp $
- *
- * Ethereal - Network traffic analyzer
- * By Gerald Combs <gerald@zing.org>
- * Copyright 1998 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 __DFILTER_INT_H__
-#define __DFILTER_INT_H__
-
-#ifndef __IPV4_H__
-#include "ipv4.h"
-#endif
-
-/* in dfilter-scanner.l */
-GByteArray *byte_str_to_guint8_array(const char *s);
-void dfilter_scanner_text(char*);
-void dfilter_scanner_cleanup(void);
-
-/* in dfilter-grammar.y */
-extern dfilter *global_df;
-
-/* Here we provide interfaces to make our scanner act and look like lex */
-int dfilter_lex(void);
-void dfilter_error(char *s);
-
-/* Report an error during compilation of a filter; this is called by code
- * other than parser code, so all it does is record that an error occurred,
- * so that even if the filter is nominally syntactically valid, we still
- * fail.
- */
-#if __GNUC__ == 2
-void dfilter_fail(char *fmt, ...)
- __attribute__((format (printf, 1, 2)));
-#else
-void dfilter_fail(char *fmt, ...);
-#endif
-
-/* functions that dfilter-grammar.y needs during parsing*/
-gboolean check_relation_numeric(gint operand, GArray *a, GArray *b);
-gboolean check_relation_floating(gint operand, GArray *a, GArray *b);
-gboolean check_relation_ether(gint operand, GArray *a, GArray *b);
-gboolean check_relation_ipv4(gint operand, GArray *a, GArray *b);
-gboolean check_relation_ipv6(gint operand, GArray *a, GArray *b);
-gboolean check_relation_bytes(gint operand, GArray *a, GArray *b);
-gboolean check_relation_string(gint operand, GArray *a, GArray *b);
-
-void fill_array_numeric_variable(field_info*, GArray*, const guint8*);
-void fill_array_floating_variable(field_info*, GArray*, const guint8*);
-void fill_array_ether_variable(field_info*, GArray*, const guint8*);
-void fill_array_ipv4_variable(field_info*, GArray*, const guint8*);
-void fill_array_ipv6_variable(field_info*, GArray*, const guint8*);
-void fill_array_bytes_variable(field_info*, GArray*, const guint8*);
-void fill_array_string_variable(field_info*, GArray*, const guint8*);
-
-gboolean fill_array_numeric_value(GNode *gnode, gpointer data);
-gboolean fill_array_floating_value(GNode *gnode, gpointer data);
-gboolean fill_array_ether_value(GNode *gnode, gpointer data);
-gboolean fill_array_ipv4_value(GNode *gnode, gpointer data);
-gboolean fill_array_ipv6_value(GNode *gnode, gpointer data);
-gboolean fill_array_bytes_value(GNode *gnode, gpointer data);
-gboolean fill_array_string_value(GNode *gnode, gpointer data);
-
-#ifdef WIN32
-#define boolean truth_value
-#endif
-
-enum node_type {
- relation, /* eq, ne, gt, ge, lt, le */
- logical, /* and, or, not, xor */
- variable, /* protocol or header field id */
- existence, /* existence of a variable (protocol or hf) */
- alternation, /* &, | */
- boolean, /* true, false */
- numeric, /* uint8, uint16, or uint32 value */
- floating, /* double */
- abs_time,
- string,
- ether,
- bytes,
- ipv4,
- ipv6,
- ipxnet
-};
-
-typedef gboolean(*CheckRelationFunc) (gint operand, GArray *a, GArray *b);
-typedef void(*FillArrayFunc) (field_info*, GArray*, const guint8*);
-
-/* This struct is the parse tree node created by this grammary and used
- * directly in the display filter routines to filter packets.
- */
-typedef struct dfilter_node {
- enum node_type ntype; /* from dfilter-grammar.h */
- int elem_size; /* computed at dfilter parse time rather than
- when finding elements for each packet. Saves time
- in get_values_from_ptree() */
- CheckRelationFunc check_relation_func;
- FillArrayFunc fill_array_variable_func;
- GNodeTraverseFunc fill_array_value_func;
-
- /* copied from proto.h */
- union {
- gint relation; /* if type == relation (eq, ne, gt, ge, lt, le) */
- gint logical; /* if type == logical (and, or, not, xor) */
- gint variable; /* if type == variable (protocol or header field abbrev) */
- gint alternation; /* if type == alternation (& or |) */
-
- guint32 numeric;
- double floating;
- struct timeval abs_time; /* the whole struct, not a pointer */
- gchar *string;
- guint8 ether[6];
- ipv4_addr ipv4; /* the whole struct, not a pointer */
- guint8 ipv6[16];
- GByteArray *bytes;
- } value;
-
- /* used for byte-ranges */
- gint offset;
- guint length;
-
- /* used to indicate range should go to end of sequence */
- gboolean to_the_end;
-} dfilter_node;
-
-/* lookup an abbreviation in our token hash, returing the ID # */
-int dfilter_lookup_token(char *abbrev);
-
-#endif /* ! __DFILTER_INT_H__ */
diff --git a/epan/dfilter-scanner.l b/epan/dfilter-scanner.l
deleted file mode 100644
index b78ddcb2c4..0000000000
--- a/epan/dfilter-scanner.l
+++ /dev/null
@@ -1,366 +0,0 @@
-%{
-
-/* dfilter-scanner.l
- * Scanner for display filters
- *
- * $Id: dfilter-scanner.l,v 1.1 2000/09/27 04:54:48 gram Exp $
- *
- * Ethereal - Network traffic analyzer
- * By Gerald Combs <gerald@zing.org>
- * Copyright 1998 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.
- */
-
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
-
-#ifdef HAVE_IO_H
-#include <io.h> /* for isatty() on win32 */
-#endif
-
-#ifdef HAVE_SYS_TYPES_H
-# include <sys/types.h>
-#endif
-
-#ifndef _STDIO_H
-#include <stdio.h>
-#endif
-
-#ifndef _STRING_H
-#include <string.h>
-#endif
-
-#ifndef __G_LIB_H__
-#include <glib.h>
-#endif
-
-#ifndef __PROTO_H__
-#include "proto.h"
-#endif
-
-#ifndef __DFILTER_H__
-#include "dfilter.h"
-#endif
-
-#include "dfilter-int.h"
-
-#include "dfilter-grammar.h"
-
-/* Flex has a few routines which help us get the scanner to read
- * from a string rather than from a file. POSIX lex only provides
- * for reading from a file; any method of reading from a string
- * is inherently non-portable. Besides reading from a string,
- * we have to worry about resetting the scanner after a bad
- * parse; this too is non-portable. Combine the reset with
- * a string input, and you have major non-portability. I'll provide
- * the routines for flex here. If you really want to modify the
- * scanner and use a non-flex lex implementation, you may
- * add more ifdef's below.
- */
-#ifdef FLEX_SCANNER
-
-/* Flex has built-in support for using a string as an input source
- * instead of using a file. Nice!
- */
-YY_BUFFER_STATE string_input_buffer;
-
-/* We don't need yyunput, so use this macro to get it out of the
- * generated C file, avoiding a compiler warning about its lack of use */
-#define YY_NO_UNPUT 1
-
-#else
-
-static char *in_buffer;
-#undef getc
-#define getc(fp) (*in_buffer == 0 ? EOF : *in_buffer++)
-
-#endif
-
-
-%}
-
-whitespace [\t ]
-hex [A-Fa-f0-9]{1,2}
-hexsep [-:\.]
-minus [-]
-plus [+]
-
-%%
-
-[\t\n ]+ /* ignore whitespace */
-
-
-and|\&\& { dfilter_lval.operand = TOK_AND; return TOK_AND; }
-or|\|\| { dfilter_lval.operand = TOK_OR; return TOK_OR; }
-not|\! { dfilter_lval.operand = TOK_NOT; return TOK_NOT; }
-xor|\^\^ { dfilter_lval.operand = TOK_XOR; return TOK_XOR; }
-eq|\=\= { dfilter_lval.operand = TOK_EQ; return TOK_EQ; }
-ne|\!\= { dfilter_lval.operand = TOK_NE; return TOK_NE; }
-gt|\> { dfilter_lval.operand = TOK_GT; return TOK_GT; }
-ge|\>\= { dfilter_lval.operand = TOK_GE; return TOK_GE; }
-lt|\< { dfilter_lval.operand = TOK_LT; return TOK_LT; }
-le|\<\= { dfilter_lval.operand = TOK_LE; return TOK_LE; }
-
-\[{whitespace}*-?[0-9]+{whitespace}*:{whitespace}*[0-9]+{whitespace}*\] { /* range [ x : y ] */
-
- char *byterange_string = g_strdup(yytext);
- char *s = byterange_string + 1; /* I don't want the first '[' */
- char *p;
-
- /* Get the offset from the string */
- if ((p = strtok(s, ":"))) {
- dfilter_lval.byte_range.offset = strtol(p, NULL, 10);
- }
- else {
- g_free(byterange_string);
- return 0;
- }
-
- /* Get the Length from the string */
- if ((p = strtok(NULL, "]"))) {
- dfilter_lval.byte_range.length = strtoul(p, NULL, 10);
- }
- else {
- g_free(byterange_string);
- return 0;
- }
- g_free(byterange_string);
- return T_VAL_BYTE_RANGE;
-}
-
-\[{whitespace}*-?[0-9]+{whitespace}*\] { /* range [ x ] */
-
- char *byterange_string = g_strdup(yytext);
- char *s = byterange_string + 1; /* I don't want the first '[' */
- char *p;
-
- /* Get the offset from the string */
- if ((p = strtok(s, "]"))) {
- dfilter_lval.byte_range.offset = strtol(p, NULL, 10);
- }
- else {
- g_free(byterange_string);
- return 0;
- }
-
- dfilter_lval.byte_range.length = 0;
- g_free(byterange_string);
- return T_VAL_BYTE_RANGE;
-}
-
-{hex}({hexsep}{hex})+ { /* byte string, any length */
- dfilter_lval.string = g_strdup(yytext);
- return T_VAL_BYTE_STRING;
-}
-
-
-0[xX][A-Fa-f0-9]+ { /* hex values */
- dfilter_lval.string = g_strdup(yytext);
- return T_VAL_UNQUOTED_STRING;
-}
-
-[A-Za-z0-9\:][A-Za-z0-9\.\_\-\:]+ {
- /* looks like a protocol, field name, or hostname */
-
- int retval = 0;
- enum ftenum ftype;
- dfilter_lval.variable.id = dfilter_lookup_token(yytext);
- if (dfilter_lval.variable.id < 0) {
- dfilter_lval.string = g_strdup(yytext);
- return T_VAL_UNQUOTED_STRING;
- }
-
- ftype = proto_registrar_get_ftype(dfilter_lval.variable.id);
- switch (ftype) {
- case FT_NONE:
- retval = T_FT_NONE;
- break;
- case FT_BOOLEAN:
- retval = T_FT_BOOLEAN;
- break;
- case FT_UINT8:
- retval = T_FT_UINT8;
- break;
- case FT_UINT16:
- retval = T_FT_UINT16;
- break;
- case FT_UINT24:
- retval = T_FT_UINT24;
- break;
- case FT_UINT32:
- retval = T_FT_UINT32;
- break;
- case FT_INT8:
- retval = T_FT_INT8;
- break;
- case FT_INT16:
- retval = T_FT_INT16;
- break;
- case FT_INT24:
- retval = T_FT_INT24;
- break;
- case FT_INT32:
- retval = T_FT_INT32;
- break;
- case FT_DOUBLE:
- retval = T_FT_DOUBLE;
- break;
- case FT_ABSOLUTE_TIME:
- dfilter_fail("Sorry, you can't filter on field \"%s\", as we don't yet support filtering on time-of-day values.",
- yytext);
- retval = 0;
- break;
- case FT_RELATIVE_TIME:
- dfilter_fail("Sorry, you can't filter on field \"%s\", as we don't yet support filtering on time-delta values.",
- yytext);
- retval = 0;
- break;
- case FT_STRING:
- case FT_STRINGZ:
- case FT_UINT_STRING:
- retval = T_FT_STRING;
- break;
- case FT_ETHER:
- retval = T_FT_ETHER;
- break;
- case FT_BYTES:
- retval = T_FT_BYTES;
- break;
- case FT_IPv4:
- retval = T_FT_IPv4;
- break;
- case FT_IPv6:
- retval = T_FT_IPv6;
- break;
- case FT_IPXNET:
- retval = T_FT_IPXNET;
- break;
- default:
- printf("ftype for %s is %d\n", yytext, ftype);
- g_assert_not_reached();
- retval = 0;
- break;
- }
- dfilter_lval.variable.type = retval;
- return retval;
-}
-
-({plus}|{minus})?[0-9]+ { /* decimal and octal integers */
- dfilter_lval.string = g_strdup(yytext);
- return T_VAL_UNQUOTED_STRING;
-}
-
-({plus}|{minus})?([0-9]+|[0-9]+\.[0-9]+|\.[0-9]+)([eE]({plus}|{minus})?[0-9]+)? {
- /* I'm trying to capture all floating points here, and
- * am using the strtod manpage as the description of
- * valid formats */
- dfilter_lval.string = g_strdup(yytext);
- return T_VAL_UNQUOTED_STRING;
-}
-
-[0-9\:\.]+ {
- dfilter_lval.string = g_strdup(yytext);
- return T_VAL_UNQUOTED_STRING;
-}
-
-\"[^"]+\" {
- int length;
-
- /* Don't copy the first quote. */
- dfilter_lval.string = g_strdup(&yytext[1]);
-
- /* Chop of the final quote mark. */
- length = strlen(dfilter_lval.string);
- g_assert(length > 0);
- dfilter_lval.string[length - 1] = 0;
-
- return T_VAL_QUOTED_STRING;
-}
-
-. return yytext[0];
-%%
-
-/* Resets scanner and assigns the char* argument
- * as the text to scan
- */
-void
-dfilter_scanner_text(char *text)
-{
-#ifdef FLEX_SCANNER
- string_input_buffer = yy_scan_string(text);
-#else
- in_buffer = text;
-#endif
-}
-
-void
-dfilter_scanner_cleanup(void)
-{
-#ifdef FLEX_SCANNER
- yy_delete_buffer(string_input_buffer);
-#else
- /* There is no standard way to reset a lex scanner.
- * This is necessary after a failed parse on a syntactically
- * incorrect display filter. You have to reset the scanner
- * so that yy_lex() doesn't start scanning from the middle
- * of the previous input string.
- */
-#endif
-}
-
-/* Flex has an option '%option noyywrap' so that I don't have to
- * provide this yywrap function, but in order to maintain portability,
- * I'll just use this yywrap() function.
- */
-int
-yywrap()
-{
- return 1; /* stop at EOF, instead of looking for next file */
-}
-
-/* converts a string representing a byte array
- * to a guint8 array.
- *
- * Returns a non-null GByteArray pointer on success, NULL on failure.
- */
-GByteArray*
-byte_str_to_guint8_array(const char *s)
-{
- GByteArray *barray;
- guint8 val;
- char *byte_str;
- char *p, *str;
-
- barray = g_byte_array_new();
- /* XXX - don't use global_df, but pass in pointer to GSList* */
- global_df->list_of_byte_arrays = g_slist_append(global_df->list_of_byte_arrays, barray);
-
- /* Local copy of string, since strtok will munge it */
- byte_str = g_strdup(s);
- str = byte_str;
- while ((p = strtok(str, "-:."))) {
- val = (guint8) strtoul(p, NULL, 16);
- g_byte_array_append(barray, &val, 1);
-
- /* subsequent calls to strtok() require NULL as arg 1 */
- str = NULL;
- }
-
- g_free(byte_str);
- return barray;
-}
diff --git a/epan/dfilter.c b/epan/dfilter.c
deleted file mode 100644
index 378c109d9b..0000000000
--- a/epan/dfilter.c
+++ /dev/null
@@ -1,1086 +0,0 @@
-/* dfilter.c
- * Routines for display filters
- *
- * $Id: dfilter.c,v 1.3 2000/12/22 12:05:36 gram Exp $
- *
- * Ethereal - Network traffic analyzer
- * By Gerald Combs <gerald@zing.org>
- * Copyright 1998 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.
- */
-
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
-
-#ifdef HAVE_SYS_TYPES_H
-# include <sys/types.h>
-#endif
-
-#include <stdio.h>
-#include <string.h>
-#include <glib.h>
-
-#ifdef NEED_SNPRINTF_H
-# include "snprintf.h"
-#endif
-
-#include "proto.h"
-#include "dfilter.h"
-#include "dfilter-int.h"
-#include "dfilter-grammar.h"
-
-int dfilter_parse(void); /* yacc entry-point */
-
-#define DFILTER_LEX_ABBREV_OFFSET 2000
-
-/* Balanced tree of abbreviations and IDs */
-GTree *dfilter_tokens = NULL;
-
-/* Comparision function for tree insertion. A wrapper around strcmp() */
-static int g_strcmp(gconstpointer a, gconstpointer b);
-
-/* Silly global variables used to pass parameter to check_relation_bytes() */
-int bytes_offset = 0;
-int bytes_length = 0;
-gboolean bytes_to_the_end = FALSE;
-
-YYSTYPE yylval;
-
-/* Global error message space for dfilter_compile errors */
-gchar dfilter_error_msg_buf[1024];
-gchar *dfilter_error_msg; /* NULL when no error resulted */
-
-static gboolean dfilter_apply_node(GNode *gnode, proto_tree *ptree, const guint8 *pd);
-static gboolean check_relation(gint operand, GNode *a, GNode *b, proto_tree *ptree, const guint8 *pd);
-static gboolean check_logical(gint operand, GNode *a, GNode *b, proto_tree *ptree, const guint8 *pd);
-static GArray* get_values_from_ptree(dfilter_node *dnode, proto_tree *ptree, const guint8 *pd);
-static GArray* get_values_from_dfilter(dfilter_node *dnode, GNode *gnode);
-static gboolean check_existence_in_ptree(dfilter_node *dnode, proto_tree *ptree);
-static void clear_byte_array(gpointer data, gpointer user_data);
-
-/* this is not so pretty. I need my own g_array "function" (macro) to
- * retreive the pointer to the data stored in an array cell. I need this
- * for type ether.. GArray makes it easy for me to store 6 bytes inside an array
- * cell, but hard to retrieve it.
- */
-#define g_array_index_ptr(a,s,i) (((guint8*) (a)->data) + (i*s))
-
-extern int hf_text_only; /* in proto.c */
-
-void
-dfilter_init(void)
-{
- int i, num_symbols, symbol;
- char *s;
-
- dfilter_tokens = g_tree_new(g_strcmp);
-
- /* Add the header field and protocol abbrevs to the symbol table */
- num_symbols = proto_registrar_n();
-
- for (i=0; i < num_symbols; i++) {
- if (i == hf_text_only) {
- continue;
- }
- s = proto_registrar_get_abbrev(i);
- g_assert(s); /* Not Null */
- g_assert(s[0] != 0); /* Not empty string */
- /* Make sure we don't have duplicate abbreviation */
- if (g_tree_lookup(dfilter_tokens, s)) {
- g_message("Already have abbreviation \"%s\"", s);
- g_assert(0);
- }
- symbol = DFILTER_LEX_ABBREV_OFFSET + i;
- g_tree_insert(dfilter_tokens, s, GINT_TO_POINTER(symbol));
- }
-}
-
-void
-dfilter_cleanup(void)
-{
- if (dfilter_tokens)
- g_tree_destroy(dfilter_tokens);
-}
-
-/* Compiles the textual representation of the display filter into a tree
- * of operations to perform. Can be called multiple times, compiling a new
- * display filter each time, without having to clear any memory used, since
- * dfilter_compile will take care of that automatically.
- *
- * Returns 0 on success, non-zero on failure.
- *
- * On success, sets the "dfilter *" pointed to by its second argument
- * either to a null pointer (if the filter is a null filter, as
- * generated by an all-blank string) or to a pointer to a newly-allocated
- * dfilter structure (if the filter isn't null).
- *
- * On failure, "dfilter_error_msg" points to an appropriate error message.
- * This error message is a global string, so another invocation of
- * dfilter_compile will clear it. If the caller needs is stored, he
- * needs to g_strdup it himself.
- */
-int
-dfilter_compile(gchar *dfilter_text, dfilter **dfp)
-{
- dfilter *df;
- int retval;
-
- g_assert(dfilter_text != NULL);
-
- df = dfilter_new();
-
- /* tell the scanner to use the filter string as input */
- dfilter_scanner_text(dfilter_text);
-
- /* Assign global variable so dfilter_parse knows which dfilter we're
- * talking about. Reset the global error message.
- */
- global_df = df;
- dfilter_error_msg = NULL;
-
- /* The magic happens right here. */
- retval = dfilter_parse();
-
- /* clean up lex */
- dfilter_scanner_cleanup();
-
- /* Errors not found by the parser may not cause the parse to
- * fail; if "dfilter_error_msg" is set, it means somebody
- * else called "dfilter_fail()", e.g. the lexical analyzer,
- * so treat that as a parse error. */
- if (dfilter_error_msg != NULL)
- retval = 1;
-
- if (retval != 0) {
- if (dfilter_error_msg == NULL) {
- snprintf(dfilter_error_msg_buf, sizeof(dfilter_error_msg_buf),
- "Unable to parse filter string \"%s\".",
- dfilter_text);
- dfilter_error_msg = &dfilter_error_msg_buf[0];
- }
- }
-
- /* Set global_df to NULL just to be tidy. */
- global_df = NULL;
-
- if (retval == 0) {
- /* Success. Check if the filter is empty; if so, discard
- * it and set "*dfp" to NULL, otherwise set "*dfp" to
- * point to the filter. */
- if (df->dftree == NULL) {
- /* The filter is empty. */
- dfilter_destroy(df);
- df = NULL;
- }
- *dfp = df;
- } else {
- /* Failure. Destroy the filter. */
- dfilter_destroy(df);
- df = NULL;
- }
- return retval;
-}
-
-/* Allocates new dfilter, initializes values, and returns pointer to dfilter */
-dfilter*
-dfilter_new(void)
-{
- dfilter *df;
-
- df = g_malloc(sizeof(dfilter));
-
- df->dftree = NULL;
- df->node_memchunk = g_mem_chunk_new("df->node_memchunk",
- sizeof(dfilter_node), 20 * sizeof(dfilter_node), G_ALLOC_ONLY);
- df->list_of_byte_arrays = NULL;
- df->list_of_strings = NULL;
-
- return df;
-}
-
-static void
-free_string(gpointer data, gpointer user_data)
-{
- char *string = data;
- if (string)
- g_free(string);
-}
-
-/* Frees all memory used by dfilter, and frees dfilter itself */
-void
-dfilter_destroy(dfilter *df)
-{
- if (!df)
- return;
-
- if (df->dftree != NULL)
- g_node_destroy(df->dftree);
-
- /* clear the memory that the tree was using for nodes */
- if (df->node_memchunk)
- g_mem_chunk_reset(df->node_memchunk);
-
- /* clear the memory that the tree was using for byte arrays */
- if (df->list_of_byte_arrays) {
- g_slist_foreach(df->list_of_byte_arrays, clear_byte_array, NULL);
- g_slist_free(df->list_of_byte_arrays);
- }
-
- /* clear the allocated strings */
- if (df->list_of_strings) {
- g_slist_foreach(df->list_of_strings, free_string, NULL);
- g_slist_free(df->list_of_strings);
- }
-
- df->dftree = NULL;
- df->list_of_byte_arrays = NULL;
- df->list_of_strings = NULL;
-
- /* Git rid of memchunk */
- if (df->node_memchunk)
- g_mem_chunk_destroy(df->node_memchunk);
-
- g_free(df);
-}
-
-
-static void
-clear_byte_array(gpointer data, gpointer user_data)
-{
- GByteArray *barray = data;
- if (barray)
- g_byte_array_free(barray, TRUE);
-}
-
-/* Called when the yacc grammar finds a parsing error */
-void
-dfilter_error(char *s)
-{
-}
-
-/* Called when an error other than a parsing error occurs. */
-void
-dfilter_fail(char *format, ...)
-{
- va_list ap;
-
- /* If we've already reported one error, don't overwrite it with this
- * one. */
- if (dfilter_error_msg != NULL)
- return;
-
- va_start(ap, format);
- vsnprintf(dfilter_error_msg_buf, sizeof dfilter_error_msg_buf, format, ap);
- dfilter_error_msg = dfilter_error_msg_buf;
- va_end(ap);
-}
-
-/* lookup an abbreviation in our token tree, returing the ID #
- * If the abbreviation doesn't exit, returns -1 */
-int dfilter_lookup_token(char *abbrev)
-{
- int value;
-
- g_assert(abbrev != NULL);
- value = GPOINTER_TO_INT(g_tree_lookup(dfilter_tokens, abbrev));
-
- if (value < DFILTER_LEX_ABBREV_OFFSET) {
- return -1;
- }
- return value - DFILTER_LEX_ABBREV_OFFSET;
-}
-
-static int
-g_strcmp(gconstpointer a, gconstpointer b)
-{
- return strcmp((const char*)a, (const char*)b);
-}
-
-
-gboolean
-dfilter_apply(dfilter *dfcode, proto_tree *ptree, const guint8* pd, guint pd_len)
-{
- gboolean retval;
- if (dfcode == NULL)
- return FALSE;
- retval = dfilter_apply_node(dfcode->dftree, ptree, pd);
- return retval;
-}
-
-static gboolean
-dfilter_apply_node(GNode *gnode, proto_tree *ptree, const guint8* pd)
-{
- GNode *gnode_a, *gnode_b;
- dfilter_node *dnode = (dfilter_node*) (gnode->data);
-
- /* We'll get 2 NULLs if we don't have children */
- gnode_a = g_node_nth_child(gnode, 0);
- gnode_b = g_node_nth_child(gnode, 1);
-
- switch(dnode->ntype) {
- case variable:
- /* We'll never see this case because if the parser finds the name of
- * a variable, it will cause it to be an 'existence' operation.
- */
- g_assert_not_reached();
-
- case logical:
- g_assert(gnode_a);
- return check_logical(dnode->value.logical, gnode_a, gnode_b, ptree, pd);
-
- case relation:
- g_assert(gnode_a && gnode_b);
- return check_relation(dnode->value.relation, gnode_a, gnode_b, ptree, pd);
-
- case alternation:
- g_assert_not_reached();
- /* not coded yet */
-
- case numeric:
- case floating:
- case ipv4:
- case ipv6:
- case boolean:
- case ether:
- case string:
- case abs_time:
- case bytes:
- case ipxnet:
- /* the only time we'll see these at this point is if the display filter
- * is really wacky. (like simply "192.168.1.1"). The parser as it stands
- * now let these by. Just return TRUE */
- g_assert(!gnode_a && !gnode_b);
- return TRUE;
-
- case existence: /* checking the existence of a protocol or hf*/
- g_assert(!gnode_a && !gnode_b);
- return check_existence_in_ptree(dnode, ptree);
- }
-
- g_assert_not_reached();
- return FALSE;
-}
-
-static gboolean
-check_logical(gint operand, GNode *a, GNode *b, proto_tree *ptree, const guint8 *pd)
-{
- gboolean val_a = dfilter_apply_node(a, ptree, pd);
- gboolean val_b;
-
- switch(operand) {
- case TOK_AND:
- g_assert(b);
- return (val_a && dfilter_apply_node(b, ptree, pd));
- case TOK_OR:
- g_assert(b);
- return (val_a || dfilter_apply_node(b, ptree, pd));
- case TOK_XOR:
- g_assert(b);
- val_b = dfilter_apply_node(b, ptree, pd);
- return ( ( val_a || val_b ) && ! ( val_a && val_b ) );
- case TOK_NOT:
- return (!val_a);
- default:
- g_assert_not_reached();
- }
- g_assert_not_reached();
- return FALSE;
-}
-
-
-static void
-free_array_of_byte_arrays(GArray *array)
-{
- int i, len;
- GByteArray *ba_ptr;
-
- len = array->len;
-
- for (i = 0; i < len ; i++) {
- ba_ptr = g_array_index(array, GByteArray*, i);
- g_byte_array_free(ba_ptr, TRUE);
- }
-}
-
-/* this is inefficient. I get arrays for both a and b that represent all the values present. That is,
- * if a is bootp.option, e.g., i'll get an array showing all the bootp.option values in the protocol
- * tree. Then I'll get an array for b, which more than likely is a single int, and then I'll compare
- * them all. It makes my coding easier in the beginning, but I should change this to make it run
- * faster.
- */
-static gboolean
-check_relation(gint operand, GNode *a, GNode *b, proto_tree *ptree, const guint8* pd)
-{
- dfilter_node *node_a = (dfilter_node*) (a->data);
- dfilter_node *node_b = (dfilter_node*) (b->data);
- GArray *vals_a, *vals_b;
- gboolean retval;
-
-
- if (node_a->ntype == variable)
- vals_a = get_values_from_ptree(node_a, ptree, pd);
- else
- vals_a = get_values_from_dfilter(node_a, a);
-
- if (node_b->ntype == variable)
- vals_b = get_values_from_ptree(node_b, ptree, pd);
- else
- vals_b = get_values_from_dfilter(node_b, b);
-
- retval = node_a->check_relation_func(operand, vals_a, vals_b);
-
- /* Free GByteArrays alloated by fill_array_bytes_variable() */
- if (node_a->fill_array_variable_func == fill_array_bytes_variable) {
- free_array_of_byte_arrays(vals_a);
- }
-
- if (node_b->fill_array_variable_func == fill_array_bytes_variable) {
- free_array_of_byte_arrays(vals_b);
- }
-
- g_array_free(vals_a, FALSE);
- g_array_free(vals_b, FALSE);
-
- return retval;
-}
-
-
-static gboolean
-check_existence_in_ptree(dfilter_node *dnode, proto_tree *ptree)
-{
- int target;
-
- target = dnode->value.variable;
- return proto_check_for_protocol_or_field(ptree, target);
-}
-
-static GArray*
-get_values_from_ptree(dfilter_node *dnode, proto_tree *ptree, const guint8 *pd)
-{
- GArray *result_array;
- GPtrArray *finfo_array;
- int i, len;
- field_info *finfo;
-
- /* Prepare the array for results */
- g_assert(dnode->elem_size > 0);
- result_array = g_array_new(FALSE, FALSE, dnode->elem_size);
-
- /* Set bytes_offset, bytes_length, and bytes_to_the_end
- * for this dnode
- */
-
- bytes_offset = dnode->offset;
- bytes_length = dnode->length;
- bytes_to_the_end = dnode->to_the_end;
-
- /* Cull the finfos from the proto_tree */
- finfo_array = proto_get_finfo_ptr_array(ptree, dnode->value.variable);
- if (!finfo_array) {
- return result_array;
- }
-
- len = g_ptr_array_len(finfo_array);
-
- for (i = 0; i < len; i++) {
- finfo = g_ptr_array_index(finfo_array, i);
- dnode->fill_array_variable_func(finfo, result_array, pd);
- }
-
- g_ptr_array_free(finfo_array, FALSE);
-
- return result_array;
-}
-
-
-void
-fill_array_numeric_variable(field_info *finfo, GArray *array, const guint8 *pd)
-{
- g_array_append_val(array, finfo->value.numeric);
-}
-
-void
-fill_array_floating_variable(field_info *finfo, GArray *array, const guint8 *pd)
-{
- g_array_append_val(array, finfo->value.floating);
-}
-
-void
-fill_array_ether_variable(field_info *finfo, GArray *array, const guint8 *pd)
-{
- /* hmmm, yes, I *can* copy a pointer instead of memcpy() */
- g_array_append_val(array, finfo->value.ether);
-}
-
-void
-fill_array_ipv4_variable(field_info *finfo, GArray *array, const guint8 *pd)
-{
- /* hmmm, yes, I *can* copy a pointer instead of memcpy() */
- g_array_append_val(array, finfo->value.ipv4);
-}
-
-void
-fill_array_ipv6_variable(field_info *finfo, GArray *array, const guint8 *pd)
-{
- /* hmmm, yes, I *can* copy a pointer instead of memcpy() */
- g_array_append_val(array, finfo->value.ipv6);
-}
-
-void
-fill_array_string_variable(field_info *finfo, GArray *array, const guint8 *pd)
-{
- g_array_append_val(array, finfo->value.string);
-}
-
-void
-fill_array_bytes_variable(field_info *finfo, GArray *array, const guint8 *pd)
-{
- GByteArray *barray;
- guint read_start, pkt_end, read_len;
-
- if (bytes_offset < 0) {
- /* Handle negative byte offsets */
- bytes_offset = finfo->length + bytes_offset;
- if (bytes_offset < 0) {
- return;
- }
- }
-
- /* Check to make sure offset exists for this field */
- if (bytes_offset >= finfo->length) {
- return;
- }
-
- pkt_end = finfo->start + finfo->length;
- read_start = finfo->start + bytes_offset;
- if(bytes_to_the_end){
- read_len = pkt_end - read_start;;
- }
- else {
- read_len = bytes_length;
- }
- /* Check to make sure entire length requested is inside field */
- if (pkt_end < read_start + read_len) {
- return;
- }
-
- barray = g_byte_array_new();
- g_byte_array_append(barray, pd + read_start, read_len);
- g_array_append_val(array, barray);
-}
-
-static GArray*
-get_values_from_dfilter(dfilter_node *dnode, GNode *gnode)
-{
- GArray *array;
-
- g_assert(dnode->elem_size > 0);
- array = g_array_new(FALSE, FALSE, dnode->elem_size);
-
- g_node_traverse(gnode, G_IN_ORDER, G_TRAVERSE_ALL, -1,
- dnode->fill_array_value_func, array);
- return array;
-}
-
-gboolean fill_array_numeric_value(GNode *gnode, gpointer data)
-{
- GArray *array = (GArray*)data;
- dfilter_node *dnode = (dfilter_node*) (gnode->data);
-
- g_array_append_val(array, dnode->value.numeric);
- return FALSE; /* FALSE = do not end traversal of GNode tree */
-}
-
-gboolean fill_array_floating_value(GNode *gnode, gpointer data)
-{
- GArray *array = (GArray*)data;
- dfilter_node *dnode = (dfilter_node*) (gnode->data);
-
- g_array_append_val(array, dnode->value.floating);
- return FALSE; /* FALSE = do not end traversal of GNode tree */
-}
-
-gboolean fill_array_ether_value(GNode *gnode, gpointer data)
-{
- GArray *array = (GArray*)data;
- dfilter_node *dnode = (dfilter_node*) (gnode->data);
-
- g_array_append_val(array, dnode->value.ether);
-
- return FALSE; /* FALSE = do not end traversal of GNode tree */
-}
-
-gboolean fill_array_ipv4_value(GNode *gnode, gpointer data)
-{
- GArray *array = (GArray*)data;
- dfilter_node *dnode = (dfilter_node*) (gnode->data);
-
- g_array_append_val(array, dnode->value.ipv4);
-
- return FALSE; /* FALSE = do not end traversal of GNode tree */
-}
-
-gboolean fill_array_ipv6_value(GNode *gnode, gpointer data)
-{
- GArray *array = (GArray*)data;
- dfilter_node *dnode = (dfilter_node*) (gnode->data);
-
- g_array_append_val(array, dnode->value.ipv6);
-
- return FALSE; /* FALSE = do not end traversal of GNode tree */
-}
-
-gboolean fill_array_bytes_value(GNode *gnode, gpointer data)
-{
- GArray *array = (GArray*)data;
- dfilter_node *dnode = (dfilter_node*) (gnode->data);
- GByteArray *barray = dnode->value.bytes;
-
- g_array_append_val(array, barray);
-
- return FALSE; /* FALSE = do not end traversal of GNode tree */
-}
-
-gboolean fill_array_string_value(GNode *gnode, gpointer data)
-{
- GArray *array = (GArray*)data;
- dfilter_node *dnode = (dfilter_node*) (gnode->data);
-
- g_array_append_val(array, dnode->value.string);
-
- return FALSE; /* FALSE = do not end traversal of GNode tree */
-}
-
-gboolean check_relation_numeric(gint operand, GArray *a, GArray *b)
-{
- int i, j, len_a, len_b;
- guint32 val_a;
-
- len_a = a->len;
- len_b = b->len;
-
-
- switch(operand) {
- case TOK_EQ:
- for(i = 0; i < len_a; i++) {
- val_a = g_array_index(a, guint32, i);
- for (j = 0; j < len_b; j++) {
- if (val_a == g_array_index(b, guint32, j))
- return TRUE;
- }
- }
- return FALSE;
-
- case TOK_NE:
- for(i = 0; i < len_a; i++) {
- val_a = g_array_index(a, guint32, i);
- for (j = 0; j < len_b; j++) {
- if (val_a != g_array_index(b, guint32, j))
- return TRUE;
- }
- }
- return FALSE;
-
- case TOK_GT:
- for(i = 0; i < len_a; i++) {
- val_a = g_array_index(a, guint32, i);
- for (j = 0; j < len_b; j++) {
- if (val_a > g_array_index(b, guint32, j))
- return TRUE;
- }
- }
- return FALSE;
-
- case TOK_GE:
- for(i = 0; i < len_a; i++) {
- val_a = g_array_index(a, guint32, i);
- for (j = 0; j < len_b; j++) {
- if (val_a >= g_array_index(b, guint32, j))
- return TRUE;
- }
- }
- return FALSE;
-
- case TOK_LT:
- for(i = 0; i < len_a; i++) {
- val_a = g_array_index(a, guint32, i);
- for (j = 0; j < len_b; j++) {
- if (val_a < g_array_index(b, guint32, j))
- return TRUE;
- }
- }
- return FALSE;
-
- case TOK_LE:
- for(i = 0; i < len_a; i++) {
- val_a = g_array_index(a, guint32, i);
- for (j = 0; j < len_b; j++) {
- if (val_a <= g_array_index(b, guint32, j))
- return TRUE;
- }
- }
- return FALSE;
-
- default:
- g_assert_not_reached();
- }
-
- g_assert_not_reached();
- return FALSE;
-}
-
-gboolean check_relation_floating(gint operand, GArray *a, GArray *b)
-{
- int i, j, len_a, len_b;
- double val_a;
-
- len_a = a->len;
- len_b = b->len;
-
-
- switch(operand) {
- case TOK_EQ:
- for(i = 0; i < len_a; i++) {
- val_a = g_array_index(a, double, i);
- for (j = 0; j < len_b; j++) {
- if (val_a == g_array_index(b, double, j))
- return TRUE;
- }
- }
- return FALSE;
-
- case TOK_NE:
- for(i = 0; i < len_a; i++) {
- val_a = g_array_index(a, double, i);
- for (j = 0; j < len_b; j++) {
- if (val_a != g_array_index(b, double, j))
- return TRUE;
- }
- }
- return FALSE;
-
- case TOK_GT:
- for(i = 0; i < len_a; i++) {
- val_a = g_array_index(a, double, i);
- for (j = 0; j < len_b; j++) {
- if (val_a > g_array_index(b, double, j))
- return TRUE;
- }
- }
- return FALSE;
-
- case TOK_GE:
- for(i = 0; i < len_a; i++) {
- val_a = g_array_index(a, double, i);
- for (j = 0; j < len_b; j++) {
- if (val_a >= g_array_index(b, double, j))
- return TRUE;
- }
- }
- return FALSE;
-
- case TOK_LT:
- for(i = 0; i < len_a; i++) {
- val_a = g_array_index(a, double, i);
- for (j = 0; j < len_b; j++) {
- if (val_a < g_array_index(b, double, j))
- return TRUE;
- }
- }
- return FALSE;
-
- case TOK_LE:
- for(i = 0; i < len_a; i++) {
- val_a = g_array_index(a, double, i);
- for (j = 0; j < len_b; j++) {
- if (val_a <= g_array_index(b, double, j))
- return TRUE;
- }
- }
- return FALSE;
-
- default:
- g_assert_not_reached();
- }
-
- g_assert_not_reached();
- return FALSE;
-}
-
-gboolean check_relation_ipv4(gint operand, GArray *a, GArray *b)
-{
- int i, j, len_a, len_b;
- ipv4_addr *ptr_a, *ptr_b;
-
- len_a = a->len;
- len_b = b->len;
-
-
- switch(operand) {
- case TOK_EQ:
- for(i = 0; i < len_a; i++) {
- ptr_a = (ipv4_addr*) g_array_index_ptr(a, sizeof(ipv4_addr), i);
- for (j = 0; j < len_b; j++) {
- ptr_b = (ipv4_addr*) g_array_index_ptr(b, sizeof(ipv4_addr), j);
- if (ipv4_addr_eq(ptr_a, ptr_b))
- return TRUE;
- }
- }
- return FALSE;
-
- case TOK_NE:
- for(i = 0; i < len_a; i++) {
- ptr_a = (ipv4_addr*) g_array_index_ptr(a, sizeof(ipv4_addr), i);
- for (j = 0; j < len_b; j++) {
- ptr_b = (ipv4_addr*) g_array_index_ptr(b, sizeof(ipv4_addr), j);
- if (ipv4_addr_ne(ptr_a, ptr_b))
- return TRUE;
- }
- }
- return FALSE;
-
- case TOK_GT:
- for(i = 0; i < len_a; i++) {
- ptr_a = (ipv4_addr*) g_array_index_ptr(a, sizeof(ipv4_addr), i);
- for (j = 0; j < len_b; j++) {
- ptr_b = (ipv4_addr*) g_array_index_ptr(b, sizeof(ipv4_addr), j);
- if (ipv4_addr_gt(ptr_a, ptr_b))
- return TRUE;
- }
- }
- return FALSE;
-
- case TOK_GE:
- for(i = 0; i < len_a; i++) {
- ptr_a = (ipv4_addr*) g_array_index_ptr(a, sizeof(ipv4_addr), i);
- for (j = 0; j < len_b; j++) {
- ptr_b = (ipv4_addr*) g_array_index_ptr(b, sizeof(ipv4_addr), j);
- if (ipv4_addr_ge(ptr_a, ptr_b))
- return TRUE;
- }
- }
- return FALSE;
-
- case TOK_LT:
- for(i = 0; i < len_a; i++) {
- ptr_a = (ipv4_addr*) g_array_index_ptr(a, sizeof(ipv4_addr), i);
- for (j = 0; j < len_b; j++) {
- ptr_b = (ipv4_addr*) g_array_index_ptr(b, sizeof(ipv4_addr), j);
- if (ipv4_addr_lt(ptr_a, ptr_b))
- return TRUE;
- }
- }
- return FALSE;
-
- case TOK_LE:
- for(i = 0; i < len_a; i++) {
- ptr_a = (ipv4_addr*) g_array_index_ptr(a, sizeof(ipv4_addr), i);
- for (j = 0; j < len_b; j++) {
- ptr_b = (ipv4_addr*) g_array_index_ptr(b, sizeof(ipv4_addr), j);
- if (ipv4_addr_le(ptr_a, ptr_b))
- return TRUE;
- }
- }
- return FALSE;
- }
-
- g_assert_not_reached();
- return FALSE;
-}
-
-gboolean check_relation_ipv6(gint operand, GArray *a, GArray *b)
-{
- int i, j, len_a, len_b;
- guint8 *ptr_a, *ptr_b;
-
- len_a = a->len;
- len_b = b->len;
-
-
- switch(operand) {
- case TOK_EQ:
- for(i = 0; i < len_a; i++) {
- ptr_a = g_array_index_ptr(a, 16, i);
- for (j = 0; j < len_b; j++) {
- ptr_b = g_array_index_ptr(b, 16, j);
- if (memcmp(ptr_a, ptr_b, 16) == 0)
- return TRUE;
- }
- }
- return FALSE;
-
- case TOK_NE:
- for(i = 0; i < len_a; i++) {
- ptr_a = g_array_index_ptr(a, 16, i);
- for (j = 0; j < len_b; j++) {
- ptr_b = g_array_index_ptr(b, 16, j);
- if (memcmp(ptr_a, ptr_b, 16) != 0)
- return TRUE;
- }
- }
- return FALSE;
- }
-
- g_assert_not_reached();
- return FALSE;
-}
-
-gboolean check_relation_ether(gint operand, GArray *a, GArray *b)
-{
- int i, j, len_a, len_b;
- guint8 *ptr_a, *ptr_b;
-
- len_a = a->len;
- len_b = b->len;
-
-
- switch(operand) {
- case TOK_EQ:
- for(i = 0; i < len_a; i++) {
- ptr_a = g_array_index_ptr(a, 6, i);
- for (j = 0; j < len_b; j++) {
- ptr_b = g_array_index_ptr(b, 6, j);
- if (memcmp(ptr_a, ptr_b, 6) == 0)
- return TRUE;
- }
- }
- return FALSE;
-
- case TOK_NE:
- for(i = 0; i < len_a; i++) {
- ptr_a = g_array_index_ptr(a, 6, i);
- for (j = 0; j < len_b; j++) {
- ptr_b = g_array_index_ptr(b, 6, j);
- if (memcmp(ptr_a, ptr_b, 6) != 0)
- return TRUE;
- }
- }
- return FALSE;
- }
-
- g_assert_not_reached();
- return FALSE;
-}
-
-gboolean check_relation_bytes(gint operand, GArray *a, GArray *b)
-{
- int i, j, len_a, len_b;
- GByteArray *ptr_a,*ptr_b;
-
- len_a = a->len;
- len_b = b->len;
-
-
- switch(operand) {
- case TOK_EQ:
- for(i = 0; i < len_a; i++) {
- ptr_a = g_array_index(a, GByteArray*, i);
- for (j = 0; j < len_b; j++) {
- ptr_b = g_array_index(b, GByteArray*, j);
- if(ptr_a->len != ptr_b->len)
- return FALSE; if (memcmp(ptr_a->data, ptr_b->data, ptr_a->len) == 0)
- return TRUE;
- }
- }
- return FALSE;
-
- case TOK_NE:
- for(i = 0; i < len_a; i++) {
- ptr_a = g_array_index(a, GByteArray*, i);
- for (j = 0; j < len_b; j++) {
- ptr_b = g_array_index(b, GByteArray*, j);
- if(ptr_a->len != ptr_b->len)
- return TRUE;
- if (memcmp(ptr_a->data, ptr_b->data, ptr_a->len) != 0)
- return TRUE;
- }
- }
- return FALSE;
-
- case TOK_GT:
- for(i = 0; i < len_a; i++) {
- ptr_a = g_array_index(a, GByteArray*, i);
- for (j = 0; j < len_b; j++) {
- ptr_b = g_array_index(b, GByteArray*, j);
- if(ptr_a->len > ptr_b->len)
- return TRUE;
- if(ptr_a->len < ptr_b->len)
- return FALSE;
- if (memcmp(ptr_a->data, ptr_b->data, ptr_a->len) > 0)
- return TRUE;
- }
- }
- return FALSE;
-
- case TOK_LT:
- for(i = 0; i < len_a; i++) {
- ptr_a = g_array_index(a, GByteArray*, i);
- for (j = 0; j < len_b; j++) {
- ptr_b = g_array_index(b, GByteArray*, j);
- if(ptr_a->len < ptr_b->len)
- return TRUE;
- if(ptr_a->len > ptr_b->len)
- return FALSE;
- if (memcmp(ptr_a->data, ptr_b->data, ptr_a->len) < 0)
- return TRUE;
- }
- }
- return FALSE;
- }
-
- g_assert_not_reached();
- return FALSE;
-}
-
-gboolean check_relation_string(gint operand, GArray *a, GArray *b)
-{
- int i, j, len_a, len_b;
- char *ptr_a, *ptr_b;
-
- len_a = a->len;
- len_b = b->len;
-
-
- switch(operand) {
- case TOK_EQ:
- for(i = 0; i < len_a; i++) {
- ptr_a = g_array_index(a, char*, i);
- for (j = 0; j < len_b; j++) {
- ptr_b = g_array_index(b, char*, j);
- if (strcmp(ptr_a, ptr_b) == 0)
- return TRUE;
- }
- }
- return FALSE;
-
- case TOK_NE:
- for(i = 0; i < len_a; i++) {
- ptr_a = g_array_index(a, char*, i);
- for (j = 0; j < len_b; j++) {
- ptr_b = g_array_index(b, char*, j);
- if (strcmp(ptr_a, ptr_b) != 0)
- return TRUE;
- }
- }
- return FALSE;
- }
-
- g_assert_not_reached();
- return FALSE;
-}
-
diff --git a/epan/dfilter.h b/epan/dfilter.h
deleted file mode 100644
index 200430001e..0000000000
--- a/epan/dfilter.h
+++ /dev/null
@@ -1,70 +0,0 @@
-/* dfilter.h
- * Definitions for display filters
- *
- * $Id: dfilter.h,v 1.1 2000/09/27 04:54:49 gram Exp $
- *
- * Ethereal - Network traffic analyzer
- * By Gerald Combs <gerald@zing.org>
- * Copyright 1998 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 __DFILTER_H__
-#define __DFILTER_H__
-
-#include "proto.h"
-
-/* dfilter_error_msg is NULL if there was no error during dfilter_compile,
- * otherwise it points to a displayable error message. */
-extern gchar *dfilter_error_msg;
-extern gchar dfilter_error_msg_buf[1024];
-
-typedef struct {
-
- GNode *dftree;
-
- /* space for dfilter_nodes */
- GMemChunk *node_memchunk;
-
- /* list of byte arrays we allocate during parse. We can traverse this list
- * faster than the tree when we go back and free the byte arrays */
- GSList *list_of_byte_arrays;
-
- /* List of strings allocated during parse. */
- GSList *list_of_strings;
-
-} dfilter;
-
-/* Initialization of the symbol table. Called once during program startup */
-void dfilter_init(void);
-
-/* Free the memory used by the symbol table. Called at program shutdown */
-void dfilter_cleanup(void);
-
-/* Allocate and initialize new dfilter struct. Returns pointer to new dfilter */
-dfilter* dfilter_new(void);
-
-/* Frees all memory used by dfilter, and frees dfilter itself */
-void dfilter_destroy(dfilter *df);
-
-/* Compile display filter text */
-int dfilter_compile(gchar* dfilter_text, dfilter** dfp);
-
-/* Apply compiled dfilter to a proto_tree */
-gboolean dfilter_apply(dfilter *df, proto_tree *ptree, const guint8* pd, guint pd_len);
-
-#endif /* ! __DFILTER_H__ */
diff --git a/epan/dfilter/.cvsignore b/epan/dfilter/.cvsignore
new file mode 100644
index 0000000000..8881f6cef9
--- /dev/null
+++ b/epan/dfilter/.cvsignore
@@ -0,0 +1,8 @@
+.cvsignore
+.deps
+scanner.c
+Makefile
+grammar.h
+grammar.out
+Makefile.in
+grammar.c
diff --git a/epan/dfilter/Makefile.am b/epan/dfilter/Makefile.am
new file mode 100644
index 0000000000..3de048250d
--- /dev/null
+++ b/epan/dfilter/Makefile.am
@@ -0,0 +1,81 @@
+# Makefile.am
+# Automake file for the GTK interface routines for Ethereal
+#
+# $Id: Makefile.am,v 1.1 2001/02/01 20:21:18 gram Exp $
+#
+# 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.
+
+# We produce an archive library. In the future, when libethereal is a
+# shared library, this will be linked into libethereal. While libethereal
+# is an archive library, any executable linking against libethereal will
+# also need to link against libftypes.
+noinst_LIBRARIES = libdfilter.a
+
+CLEANFILES = \
+ libdfilter.a \
+ *~
+
+INCLUDES = -I$(srcdir)/../.. -I$(srcdir)/$(LEMON)
+
+libdfilter_a_SOURCES = \
+ cppmagic.h \
+ dfilter.c \
+ dfilter.h \
+ dfilter-int.h \
+ dfvm.c \
+ dfvm.h \
+ gencode.c \
+ gencode.h \
+ glib-util.c \
+ glib-util.h \
+ grammar.c \
+ grammar.h \
+ scanner.c \
+ semcheck.c \
+ semcheck.h \
+ sttype-pointer.c \
+ sttype-range.c \
+ sttype-range.h \
+ sttype-string.c \
+ sttype-test.c \
+ sttype-test.h \
+ syntax-tree.c \
+ syntax-tree.h
+
+# Makefile.nmake
+EXTRA_DIST = \
+ grammar.lemon \
+ lemonflex-head.inc \
+ lemonflex-tail.inc \
+ lemon.c \
+ lempar.c \
+ scanner.l
+
+scanner.c : scanner.l
+ $(LEX) -Pdf_ -oscanner.c $(srcdir)/scanner.l
+
+scanner.o : scanner.c grammar.h
+
+LEMON=../../tools/lemon
+
+grammar.c grammar.h : grammar.lemon
+ $(LEMON)/lemon t=$(srcdir)/$(LEMON)/lempar.c $(srcdir)/grammar.lemon || \
+ (rm -f grammar.c grammar.h ; false)
+
diff --git a/epan/dfilter/cppmagic.h b/epan/dfilter/cppmagic.h
new file mode 100644
index 0000000000..92bef11eb1
--- /dev/null
+++ b/epan/dfilter/cppmagic.h
@@ -0,0 +1,14 @@
+/* $Id: cppmagic.h,v 1.1 2001/02/01 20:21:18 gram Exp $ */
+
+/**************************************** CPP definitions ***************/
+
+/* CPP magic: Concatenate two strings or macros that resolve to strings.
+ * Use CONCAT(), not _CONCAT() */
+#define _CONCAT(a,b) a ## b
+#define CONCAT(a,b) _CONCAT(a,b)
+
+/* CPP magic: Surround a string or a macro that resolves to a string with
+ * double quotes. */
+#define _STRINGIFY(a) # a
+#define STRINGIFY(a) _STRINGIFY(a)
+
diff --git a/epan/dfilter/dfilter-int.h b/epan/dfilter/dfilter-int.h
new file mode 100644
index 0000000000..e3bd84325e
--- /dev/null
+++ b/epan/dfilter/dfilter-int.h
@@ -0,0 +1,52 @@
+/* dfilter-int.h
+ * Header information for use by multiple files in the dfilter submodule.
+ *
+ * $Id: dfilter-int.h,v 1.1 2001/02/01 20:21:18 gram Exp $
+ *
+ */
+
+#ifndef DFILTER_INT_H
+#define DFILTER_INT_H
+
+#include "dfilter.h"
+#include "syntax-tree.h"
+
+#include "proto.h"
+
+/* Passed back to user */
+struct _dfilter_t {
+ GPtrArray *insns;
+ int num_registers;
+ GList **registers;
+ gboolean *attempted_load;
+};
+
+typedef struct {
+ /* Syntax Tree stuff */
+ stnode_t *st_root;
+ gboolean syntax_error;
+ GPtrArray *insns;
+ GHashTable *loaded_fields;
+ int next_insn_id;
+ int next_register;
+} dfwork_t;
+
+/* Constructor/Destructor prototypes for Lemon Parser */
+void *DfilterAlloc(void* (*)());
+void DfilterFree(void*, void (*)());
+void Dfilter(void*, int, stnode_t*, dfwork_t*);
+
+/* Scanner's lval */
+extern stnode_t *df_lval;
+
+/* Given a field abbreviation, returns the proto ID, or -1 if
+ * it doesn't exist. */
+header_field_info*
+dfilter_lookup_token(char *abbrev);
+
+/* Set dfilter_error_msg_buf and dfilter_error_msg */
+void
+dfilter_fail(char *format, ...);
+
+
+#endif
diff --git a/epan/dfilter/dfilter.c b/epan/dfilter/dfilter.c
new file mode 100644
index 0000000000..a8d249cbf4
--- /dev/null
+++ b/epan/dfilter/dfilter.c
@@ -0,0 +1,352 @@
+/* dfilter.c
+ * Main entry point for dfilter routines
+ *
+ * $Id: dfilter.c,v 1.1 2001/02/01 20:21:18 gram Exp $
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+
+#ifdef NEED_SNPRINTF_H
+#include "snprintf.h"
+#endif
+
+#include "dfilter-int.h"
+#include "syntax-tree.h"
+#include "gencode.h"
+#include "semcheck.h"
+#include "dfvm.h"
+
+
+/* Balanced tree of abbreviations and IDs */
+GTree *dfilter_tokens = NULL;
+
+#define DFILTER_TOKEN_ID_OFFSET 1
+
+/* Comparision function for tree insertion. A wrapper around strcmp() */
+static int g_strcmp(gconstpointer a, gconstpointer b);
+
+/* Global error message space for dfilter_compile errors */
+gchar dfilter_error_msg_buf[1024];
+gchar *dfilter_error_msg; /* NULL when no error resulted */
+
+/* In proto.c */
+extern int hf_text_only;
+
+/* From scanner.c */
+void df_scanner_text(const char *text);
+void df_scanner_file(FILE *fh);
+void df_scanner_cleanup(void);
+int df_lex(void);
+
+/* Holds the singular instance of our Lemon parser object */
+void* ParserObj = NULL;
+
+void
+dfilter_fail(char *format, ...)
+{
+ va_list args;
+
+ /* If we've already reported one error, don't overwite it */
+ if (dfilter_error_msg != NULL)
+ return;
+
+ va_start(args, format);
+
+ vsnprintf(dfilter_error_msg_buf, sizeof(dfilter_error_msg_buf),
+ format, args);
+ dfilter_error_msg = dfilter_error_msg_buf;
+ va_end(args);
+}
+
+
+/* Initialize the dfilter module */
+void
+dfilter_init(void)
+{
+ int id, num_symbols;
+ char *abbrev;
+ header_field_info *hfinfo, *same_name_hfinfo;
+
+ num_symbols = proto_registrar_n();
+
+ if (dfilter_tokens) {
+ /* XXX - needed? */
+ g_message("I expected hf_ids to be NULL\n");
+ g_tree_destroy(dfilter_tokens);
+
+ /* Make sure the hfinfo->same_name links are broken */
+ for (id = 0; id < num_symbols; id++) {
+ hfinfo = proto_registrar_get_nth(id);
+ hfinfo->same_name = NULL;
+ }
+ }
+ dfilter_tokens = g_tree_new(g_strcmp);
+
+ /* Populate the abbrev/ID GTree (header-field symbol table) */
+
+
+ for (id = 0; id < num_symbols; id++) {
+ if (id == hf_text_only) {
+ continue;
+ }
+ abbrev = proto_registrar_get_abbrev(id);
+ hfinfo = proto_registrar_get_nth(id);
+
+ g_assert(abbrev); /* Not Null */
+ g_assert(abbrev[0] != 0); /* Not empty string */
+
+ /* We allow multiple hfinfo's to be registered under the same
+ * abbreviation. This was done for X.25 */
+ same_name_hfinfo = g_tree_lookup(dfilter_tokens, abbrev);
+ if (same_name_hfinfo) {
+ /* Set the "same_name" pointer in the hfinfo, then
+ * allow the code after this if{} block to replace the
+ * old hfinfo with the new hfinfo in the GTree. Thus,
+ * we end up with a linked-list of same-named hfinfo's,
+ * with the root of the list being the hfinfo in the GTree */
+ hfinfo->same_name = same_name_hfinfo;
+
+ }
+ g_tree_insert(dfilter_tokens, abbrev, hfinfo);
+ }
+
+ if (ParserObj) {
+ g_message("I expected ParserObj to be NULL\n");
+ /* Free the Lemon Parser object */
+ DfilterFree(ParserObj, g_free);
+ }
+ /* Allocate an instance of our Lemon-based parser */
+ ParserObj = DfilterAlloc(g_malloc);
+
+ /* Initialize the syntax-tree sub-sub-system */
+ sttype_init();
+}
+
+/* Clean-up the dfilter module */
+void
+dfilter_cleanup(void)
+{
+ /* Free the abbrev/ID GTree */
+ if (dfilter_tokens) {
+ g_tree_destroy(dfilter_tokens);
+ dfilter_tokens = NULL;
+ }
+
+ /* Free the Lemon Parser object */
+ if (ParserObj) {
+ DfilterFree(ParserObj, g_free);
+ }
+
+ /* Clean up the syntax-tree sub-sub-system */
+ sttype_cleanup();
+}
+
+
+
+/* Lookup an abbreviation in our token tree, returing the ID #
+ * If the abbreviation doesn't exit, returns -1 */
+header_field_info*
+dfilter_lookup_token(char *abbrev)
+{
+ g_assert(abbrev != NULL);
+ return g_tree_lookup(dfilter_tokens, abbrev);
+}
+
+/* String comparison func for dfilter_token GTree */
+static int
+g_strcmp(gconstpointer a, gconstpointer b)
+{
+ return strcmp((const char*)a, (const char*)b);
+}
+
+static dfilter_t*
+dfilter_new(void)
+{
+ dfilter_t *df;
+
+ df = g_new(dfilter_t, 1);
+ df->insns = NULL;
+
+ return df;
+}
+
+/* Given a GPtrArray of instructions (dfvm_insn_t),
+ * free them. */
+static void
+free_insns(GPtrArray *insns)
+{
+ int i;
+ dfvm_insn_t *insn;
+
+ for (i = 0; i < insns->len; i++) {
+ insn = g_ptr_array_index(insns, i);
+ dfvm_insn_free(insn);
+ }
+}
+
+void
+dfilter_free(dfilter_t *df)
+{
+ if (df->insns) {
+ free_insns(df->insns);
+ }
+
+ g_free(df->registers);
+ g_free(df->attempted_load);
+ g_free(df);
+}
+
+
+static dfwork_t*
+dfwork_new(void)
+{
+ dfwork_t *dfw;
+
+ dfw = g_new(dfwork_t, 1);
+
+ dfw->st_root = NULL;
+ dfw->syntax_error = FALSE;
+ dfw->insns = NULL;
+ dfw->loaded_fields = NULL;
+ dfw->next_insn_id = 0;
+ dfw->next_register = 0;
+
+ return dfw;
+}
+
+static void
+dfwork_free(dfwork_t *dfw)
+{
+ if (dfw->st_root) {
+ stnode_free(dfw->st_root);
+ }
+
+ if (dfw->loaded_fields) {
+ g_hash_table_destroy(dfw->loaded_fields);
+ }
+
+ if (dfw->insns) {
+ free_insns(dfw->insns);
+ }
+
+ g_free(dfw);
+}
+
+
+gboolean
+dfilter_compile(gchar *text, dfilter_t **dfp)
+{
+ int token;
+ dfilter_t *dfilter;
+ dfwork_t *dfw;
+
+ dfilter_error_msg = NULL;
+
+ dfw = dfwork_new();
+
+ df_scanner_text(text);
+
+ while (1) {
+ df_lval = stnode_new(STTYPE_UNINITIALIZED, NULL);
+ token = df_lex();
+
+ /* Check for end-of-input */
+ if (token == 0) {
+ /* Tell the parser that we have reached the end of input */
+ Dfilter(ParserObj, 0, NULL, dfw);
+
+ /* Free the stnode_t that we just generated, since
+ * the parser doesn't know about it and won't free it
+ * for us. */
+ stnode_free(df_lval);
+ df_lval = NULL;
+ break;
+ }
+
+ /* Give the token to the parser */
+ Dfilter(ParserObj, token, df_lval, dfw);
+
+ if (dfw->syntax_error) {
+ break;
+ }
+ }
+
+ /* One last check for syntax error (after EOF) */
+ if (dfw->syntax_error) {
+ goto FAILURE;
+ }
+
+
+ /* Success, but was it an empty filter? If so, discard
+ * it and set *dfp to NULL */
+ if (dfw->st_root == NULL) {
+ *dfp = NULL;
+ }
+ else {
+
+ /* Check semantics and do necessary type conversion*/
+ if (!dfw_semcheck(dfw)) {
+ goto FAILURE;
+ }
+
+ /* Create bytecode */
+ dfw_gencode(dfw);
+
+ /* Tuck away the bytecode in the dfilter_t */
+ dfilter = dfilter_new();
+ dfilter->insns = dfw->insns;
+ dfw->insns = NULL;
+
+ /* Initialize run-time space */
+ dfilter->num_registers = dfw->next_register;
+ dfilter->registers = g_new0(GList*, dfilter->num_registers);
+ dfilter->attempted_load = g_new0(gboolean, dfilter->num_registers);
+
+ /* And give it to the user. */
+ *dfp = dfilter;
+ }
+ /* SUCCESS */
+ dfwork_free(dfw);
+
+ /* Reset flex */
+ df_scanner_cleanup();
+
+ return TRUE;
+
+FAILURE:
+ if (dfw) {
+ dfwork_free(dfw);
+ }
+ dfilter_fail("Unable to parse filter string \"%s\".", text);
+ *dfp = NULL;
+
+ /* Reset flex */
+ df_scanner_cleanup();
+ return FALSE;
+
+}
+
+
+gboolean
+dfilter_apply(dfilter_t *df, tvbuff_t *tvb, proto_tree *tree)
+{
+ return dfvm_apply(df, tvb, tree);
+}
+
+gboolean
+dfilter_apply_edt(dfilter_t *df, epan_dissect_t* edt)
+{
+ return dfvm_apply(df, edt->tvb, edt->tree);
+}
+
+
+void
+dfilter_dump(dfilter_t *df)
+{
+ dfvm_dump(stdout, df->insns);
+}
diff --git a/epan/dfilter/dfilter.h b/epan/dfilter/dfilter.h
new file mode 100644
index 0000000000..b9442f42c8
--- /dev/null
+++ b/epan/dfilter/dfilter.h
@@ -0,0 +1,65 @@
+/* dfilter.h
+ *
+ * $Id: dfilter.h,v 1.1 2001/02/01 20:21:18 gram Exp $
+ */
+
+#ifndef DFILTER_H
+#define DFILTER_H
+
+#include <glib.h>
+#include "epan.h"
+#include "proto.h"
+
+/* Passed back to user */
+typedef struct _dfilter_t dfilter_t;
+
+/* Module-level initialization */
+void
+dfilter_init(void);
+
+/* Module-level cleanup */
+void
+dfilter_cleanup(void);
+
+/* Compiles a string to a dfilter_t.
+ * On success, sets the dfilter* pointed to by dfp
+ * to either a NULL pointer (if the filter is a null
+ * filter, as generated by an all-blank string) or to
+ * a pointer to the newly-allocated dfilter_t
+ * structure.
+ *
+ * On failure, dfilter_error_msg points to an
+ * appropriate error message. This error message is
+ * a global string, so another invocation of
+ * dfilter_compile() will clear it. The dfilter*
+ * will be set to NULL after a failure.
+ *
+ * Returns TRUE on success, FALSE on failure.
+ */
+gboolean
+dfilter_compile(gchar *text, dfilter_t **dfp);
+
+/* Frees all memory used by dfilter, and frees
+ * the dfilter itself. */
+void
+dfilter_free(dfilter_t *df);
+
+
+/* dfilter_error_msg is NULL if there was no error during dfilter_compile,
+ * otherwise it points to a displayable error message. */
+extern gchar *dfilter_error_msg;
+
+/* Apply compiled dfilter */
+gboolean
+dfilter_apply_edt(dfilter_t *df, epan_dissect_t* edt);
+
+/* Apply compiled dfilter */
+gboolean
+dfilter_apply(dfilter_t *df, tvbuff_t *tvb, proto_tree *tree);
+
+
+/* Print bytecode of dfilter to stdout */
+void
+dfilter_dump(dfilter_t *df);
+
+#endif
diff --git a/epan/dfilter/dfvm.c b/epan/dfilter/dfvm.c
new file mode 100644
index 0000000000..bf8bfe8e17
--- /dev/null
+++ b/epan/dfilter/dfvm.c
@@ -0,0 +1,395 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "dfvm.h"
+
+dfvm_insn_t*
+dfvm_insn_new(dfvm_opcode_t op)
+{
+ dfvm_insn_t *insn;
+
+ insn = g_new(dfvm_insn_t, 1);
+ insn->op = op;
+ insn->arg1 = NULL;
+ insn->arg2 = NULL;
+ insn->arg3 = NULL;
+ insn->arg4 = NULL;
+ return insn;
+}
+
+void
+dfvm_insn_free(dfvm_insn_t *insn)
+{
+ if (insn->arg1) {
+ dfvm_value_free(insn->arg1);
+ }
+ if (insn->arg2) {
+ dfvm_value_free(insn->arg2);
+ }
+ if (insn->arg3) {
+ dfvm_value_free(insn->arg3);
+ }
+ if (insn->arg4) {
+ dfvm_value_free(insn->arg4);
+ }
+ g_free(insn);
+}
+
+
+
+dfvm_value_t*
+dfvm_value_new(dfvm_value_type_t type)
+{
+ dfvm_value_t *v;
+
+ v = g_new(dfvm_value_t, 1);
+ v->type = type;
+ return v;
+}
+
+void
+dfvm_value_free(dfvm_value_t *v)
+{
+ switch (v->type) {
+ case FVALUE:
+ fvalue_free(v->value.fvalue);
+ break;
+ default:
+ /* nothing */
+ ;
+ }
+ g_free(v);
+}
+
+
+void
+dfvm_dump(FILE *f, GPtrArray *insns)
+{
+ int id, length;
+ dfvm_insn_t *insn;
+ dfvm_value_t *arg1;
+ dfvm_value_t *arg2;
+ dfvm_value_t *arg3;
+ dfvm_value_t *arg4;
+
+ length = insns->len;
+
+ for (id = 0; id < length; id++) {
+
+ insn = g_ptr_array_index(insns, id);
+ arg1 = insn->arg1;
+ arg2 = insn->arg2;
+ arg3 = insn->arg3;
+ arg4 = insn->arg4;
+
+ switch (insn->op) {
+ case CHECK_EXISTS:
+ fprintf(f, "%05d CHECK_EXISTS\t%s\n",
+ id, proto_registrar_get_abbrev(arg1->value.numeric));
+ break;
+
+ case READ_TREE:
+ fprintf(f, "%05d READ_TREE\t\t%s -> reg#%d\n",
+ id, proto_registrar_get_abbrev(arg1->value.numeric),
+ arg2->value.numeric);
+ break;
+
+ case PUT_FVALUE:
+ fprintf(f, "%05d PUT_FVALUE\t<%s> -> reg#%d\n",
+ id, fvalue_type_name(arg1->value.fvalue),
+ arg2->value.numeric);
+ break;
+
+ case MK_RANGE:
+ fprintf(f, "%05d MK_RANGE\t\treg#%d[%d:%d] -> reg#%d\n",
+ id,
+ arg1->value.numeric,
+ arg3->value.numeric,
+ arg4->value.numeric,
+ arg2->value.numeric);
+ break;
+
+ case ANY_EQ:
+ fprintf(f, "%05d ANY_EQ\t\treg#%d == reg#%d\n",
+ id, arg1->value.numeric, arg2->value.numeric);
+ break;
+
+ case ANY_NE:
+ fprintf(f, "%05d ANY_NE\t\treg#%d == reg#%d\n",
+ id, arg1->value.numeric, arg2->value.numeric);
+ break;
+
+ case ANY_GT:
+ fprintf(f, "%05d ANY_GT\t\treg#%d == reg#%d\n",
+ id, arg1->value.numeric, arg2->value.numeric);
+ break;
+
+ case ANY_GE:
+ fprintf(f, "%05d ANY_GE\t\treg#%d == reg#%d\n",
+ id, arg1->value.numeric, arg2->value.numeric);
+ break;
+
+ case ANY_LT:
+ fprintf(f, "%05d ANY_LT\t\treg#%d == reg#%d\n",
+ id, arg1->value.numeric, arg2->value.numeric);
+ break;
+
+ case ANY_LE:
+ fprintf(f, "%05d ANY_LE\t\treg#%d == reg#%d\n",
+ id, arg1->value.numeric, arg2->value.numeric);
+ break;
+
+ case NOT:
+ fprintf(f, "%05d NOT\n", id);
+ break;
+
+ case RETURN:
+ fprintf(f, "%05d RETURN\n", id);
+ break;
+
+ case IF_TRUE_GOTO:
+ fprintf(f, "%05d IF-TRUE-GOTO\t%d\n",
+ id, arg1->value.numeric);
+ break;
+
+ case IF_FALSE_GOTO:
+ fprintf(f, "%05d IF-FALSE-GOTO\t%d\n",
+ id, arg1->value.numeric);
+ break;
+
+ default:
+ g_assert_not_reached();
+ break;
+ }
+ }
+}
+
+/* Reads a field from the proto_tree and loads the fvalues into a register,
+ * if that field has not already been read. */
+static gboolean
+read_tree(dfilter_t *df, proto_tree *tree, int field_id, int reg)
+{
+ GPtrArray *finfos;
+ field_info *finfo;
+ int i, len;
+ GList *fvalues = NULL;
+
+ /* Already loaded in this run of the dfilter? */
+ if (df->attempted_load[reg]) {
+ if (df->registers[reg]) {
+ return TRUE;
+ }
+ else {
+ return FALSE;
+ }
+ }
+
+ df->attempted_load[reg] = TRUE;
+
+ finfos = proto_get_finfo_ptr_array(tree, field_id);
+ if (!finfos) {
+ return FALSE;
+ }
+
+ len = finfos->len;
+ for (i = 0; i < len; i++) {
+ finfo = g_ptr_array_index(finfos, i);
+ fvalues = g_list_prepend(fvalues, finfo->value);
+ }
+ fvalues = g_list_reverse(fvalues);
+
+ df->registers[reg] = fvalues;
+ return TRUE;
+}
+
+
+static gboolean
+put_fvalue(dfilter_t *df, fvalue_t *fv, int reg)
+{
+ df->registers[reg] = g_list_append(NULL, fv);
+ return TRUE;
+}
+
+typedef gboolean (*FvalueCmpFunc)(fvalue_t*, fvalue_t*);
+
+static gboolean
+any_test(dfilter_t *df, FvalueCmpFunc cmp, int reg1, int reg2)
+{
+ GList *list_a, *list_b;
+
+ list_a = df->registers[reg1];
+
+ while (list_a) {
+ list_b = df->registers[reg2];
+ while (list_b) {
+ if (cmp(list_a->data, list_b->data)) {
+ return TRUE;
+ }
+ list_b = g_list_next(list_b);
+ }
+ list_a = g_list_next(list_a);
+ }
+ return FALSE;
+}
+
+
+/* Free the list nodes w/o freeing the memory that each
+ * list node points to. */
+static void
+free_register_overhead(dfilter_t* df)
+{
+ int i;
+
+ for (i = 0; i < df->num_registers; i++) {
+ if (df->registers[i]) {
+ g_list_free(df->registers[i]);
+ }
+ }
+}
+
+/* Takes the list of fvalue_t's in a register, uses fvalue_slice()
+ * to make a new list of fvalue_t's (which are ranges, or byte-slices),
+ * and puts the new list into a new register. */
+static void
+mk_range(dfilter_t *df, int from_reg, int to_reg, int start, int end)
+{
+ GList *from_list, *to_list;
+ fvalue_t *old_fv, *new_fv;
+
+ to_list = NULL;
+ from_list = df->registers[from_reg];
+
+ while (from_list) {
+ old_fv = from_list->data;
+ new_fv = fvalue_slice(old_fv, start, end);
+ /* Assert there because semcheck.c should have
+ * already caught the cases in which a slice
+ * cannot be made. */
+ g_assert(new_fv);
+ to_list = g_list_append(to_list, new_fv);
+
+ from_list = g_list_next(from_list);
+ }
+
+ df->registers[to_reg] = to_list;
+}
+
+
+
+gboolean
+dfvm_apply(dfilter_t *df, tvbuff_t *tvb, proto_tree *tree)
+{
+ int i, id, length;
+ gboolean accum = TRUE;
+ dfvm_insn_t *insn;
+ dfvm_value_t *arg1;
+ dfvm_value_t *arg2;
+ dfvm_value_t *arg3;
+ dfvm_value_t *arg4;
+
+ g_assert(tvb);
+ g_assert(tree);
+
+
+ /* Clear registers */
+ for (i = 0; i < df->num_registers; i++) {
+ df->registers[i] = NULL;
+ df->attempted_load[i] = FALSE;
+ }
+
+ length = df->insns->len;
+
+ for (id = 0; id < length; id++) {
+
+ AGAIN:
+ insn = g_ptr_array_index(df->insns, id);
+ arg1 = insn->arg1;
+ arg2 = insn->arg2;
+
+ switch (insn->op) {
+ case CHECK_EXISTS:
+ accum = proto_check_for_protocol_or_field(tree,
+ arg1->value.numeric);
+ break;
+
+ case READ_TREE:
+ accum = read_tree(df, tree,
+ arg1->value.numeric, arg2->value.numeric);
+ break;
+
+ case PUT_FVALUE:
+ accum = put_fvalue(df,
+ arg1->value.fvalue, arg2->value.numeric);
+ break;
+
+ case MK_RANGE:
+ arg3 = insn->arg3;
+ arg4 = insn->arg4;
+ mk_range(df,
+ arg1->value.numeric, arg2->value.numeric,
+ arg3->value.numeric, arg4->value.numeric);
+ break;
+
+ case ANY_EQ:
+ accum = any_test(df, fvalue_eq,
+ arg1->value.numeric, arg2->value.numeric);
+ break;
+
+ case ANY_NE:
+ accum = any_test(df, fvalue_ne,
+ arg1->value.numeric, arg2->value.numeric);
+ break;
+
+ case ANY_GT:
+ accum = any_test(df, fvalue_gt,
+ arg1->value.numeric, arg2->value.numeric);
+ break;
+
+ case ANY_GE:
+ accum = any_test(df, fvalue_ge,
+ arg1->value.numeric, arg2->value.numeric);
+ break;
+
+ case ANY_LT:
+ accum = any_test(df, fvalue_lt,
+ arg1->value.numeric, arg2->value.numeric);
+ break;
+
+ case ANY_LE:
+ accum = any_test(df, fvalue_le,
+ arg1->value.numeric, arg2->value.numeric);
+ break;
+
+ case NOT:
+ accum = !accum;
+ break;
+
+ case RETURN:
+ free_register_overhead(df);
+ return accum;
+
+ case IF_TRUE_GOTO:
+ if (accum) {
+ id = arg1->value.numeric;
+ goto AGAIN;
+ }
+ break;
+
+ case IF_FALSE_GOTO:
+ if (!accum) {
+ id = arg1->value.numeric;
+ goto AGAIN;
+ }
+ break;
+
+
+ default:
+ g_assert_not_reached();
+ break;
+ }
+ }
+
+ g_assert_not_reached();
+ return FALSE; /* to appease the compiler */
+}
diff --git a/epan/dfilter/dfvm.h b/epan/dfilter/dfvm.h
new file mode 100644
index 0000000000..d7803635da
--- /dev/null
+++ b/epan/dfilter/dfvm.h
@@ -0,0 +1,77 @@
+#ifndef DFVM_H
+#define DFVM_H
+
+#include <stdio.h>
+#include "proto.h"
+#include "dfilter-int.h"
+#include "syntax-tree.h"
+
+typedef enum {
+ EMPTY,
+ FVALUE,
+ FIELD_ID,
+ INSN_NUMBER,
+ REGISTER,
+ INTEGER
+} dfvm_value_type_t;
+
+typedef struct {
+ dfvm_value_type_t type;
+
+ union {
+ fvalue_t *fvalue;
+ guint32 numeric;
+ } value;
+
+} dfvm_value_t;
+
+
+typedef enum {
+
+ IF_TRUE_GOTO,
+ IF_FALSE_GOTO,
+ CHECK_EXISTS,
+ NOT,
+ RETURN,
+ READ_TREE,
+ PUT_FVALUE,
+ ANY_EQ,
+ ANY_NE,
+ ANY_GT,
+ ANY_GE,
+ ANY_LT,
+ ANY_LE,
+ MK_RANGE
+
+} dfvm_opcode_t;
+
+typedef struct {
+ int id;
+ int LHS;
+ dfvm_opcode_t op;
+ dfvm_value_t *arg1;
+ dfvm_value_t *arg2;
+ dfvm_value_t *arg3;
+ dfvm_value_t *arg4;
+} dfvm_insn_t;
+
+dfvm_insn_t*
+dfvm_insn_new(dfvm_opcode_t op);
+
+void
+dfvm_insn_free(dfvm_insn_t *insn);
+
+dfvm_value_t*
+dfvm_value_new(dfvm_value_type_t type);
+
+void
+dfvm_value_free(dfvm_value_t *v);
+
+void
+dfvm_dump(FILE *f, GPtrArray *insns);
+
+gboolean
+dfvm_apply(dfilter_t *df, tvbuff_t *tvb, proto_tree *tree);
+
+
+#endif
diff --git a/epan/dfilter/gencode.c b/epan/dfilter/gencode.c
new file mode 100644
index 0000000000..61c5546cb6
--- /dev/null
+++ b/epan/dfilter/gencode.c
@@ -0,0 +1,299 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "dfilter-int.h"
+#include "dfvm.h"
+#include "syntax-tree.h"
+#include "sttype-range.h"
+#include "sttype-test.h"
+#include "ftypes/ftypes.h"
+#include "gdebug.h"
+
+static void
+gencode(dfwork_t *dfw, stnode_t *st_node);
+
+static void
+dfw_append_insn(dfwork_t *dfw, dfvm_insn_t *insn)
+{
+ insn->id = dfw->next_insn_id;
+ dfw->next_insn_id++;
+ g_ptr_array_add(dfw->insns, insn);
+}
+
+/* returns register number */
+static int
+dfw_append_read_tree(dfwork_t *dfw, int field_id)
+{
+ dfvm_insn_t *insn;
+ dfvm_value_t *val1, *val2;
+ int reg = -1;
+
+ /* Keep track of which registers
+ * were used for which field_id's so that we
+ * can re-use registers. */
+ reg = GPOINTER_TO_UINT(
+ g_hash_table_lookup(dfw->loaded_fields,
+ GUINT_TO_POINTER(field_id)));
+ if (reg) {
+ /* Reg's are stored in has as reg+1, so
+ * that the non-existence of a field_id in
+ * the hash, or 0, can be differentiated from
+ * a field_id being loaded into register #0. */
+ reg--;
+ }
+ else {
+ reg = dfw->next_register++;
+ g_hash_table_insert(dfw->loaded_fields,
+ GUINT_TO_POINTER(field_id),
+ GUINT_TO_POINTER(reg + 1));
+ }
+
+ insn = dfvm_insn_new(READ_TREE);
+ val1 = dfvm_value_new(FIELD_ID);
+ val1->value.numeric = field_id;
+ val2 = dfvm_value_new(REGISTER);
+ val2->value.numeric = reg;
+
+ insn->arg1 = val1;
+ insn->arg2 = val2;
+ dfw_append_insn(dfw, insn);
+
+ return reg;
+}
+
+/* returns register number */
+static int
+dfw_append_put_fvalue(dfwork_t *dfw, fvalue_t *fv)
+{
+ dfvm_insn_t *insn;
+ dfvm_value_t *val1, *val2;
+ int reg;
+
+ insn = dfvm_insn_new(PUT_FVALUE);
+ val1 = dfvm_value_new(FVALUE);
+ val1->value.fvalue = fv;
+ val2 = dfvm_value_new(REGISTER);
+ reg = dfw->next_register++;
+ val2->value.numeric = reg;
+ insn->arg1 = val1;
+ insn->arg2 = val2;
+ dfw_append_insn(dfw, insn);
+
+ return reg;
+}
+
+/* returns register number */
+static int
+dfw_append_mk_range(dfwork_t *dfw, stnode_t *node)
+{
+ int hf_reg, reg;
+ header_field_info *hfinfo;
+ dfvm_insn_t *insn;
+ dfvm_value_t *val;
+
+ hfinfo = sttype_range_hfinfo(node);
+ hf_reg = dfw_append_read_tree(dfw, hfinfo->id);
+
+ insn = dfvm_insn_new(MK_RANGE);
+
+ val = dfvm_value_new(REGISTER);
+ val->value.numeric = hf_reg;
+ insn->arg1 = val;
+
+ val = dfvm_value_new(REGISTER);
+ reg =dfw->next_register++;
+ val->value.numeric = reg;
+ insn->arg2 = val;
+
+ val = dfvm_value_new(INTEGER);
+ val->value.numeric = sttype_range_start(node);
+ insn->arg3 = val;
+
+ val = dfvm_value_new(INTEGER);
+ val->value.numeric = sttype_range_end(node);
+ insn->arg4 = val;
+
+ dfw_append_insn(dfw, insn);
+
+ return reg;
+}
+
+
+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;
+
+ fvalue_t *junk = NULL;
+
+ 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->id);
+
+ 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->id);
+
+ 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 {
+ g_assert_not_reached();
+ }
+
+ insn = dfvm_insn_new(op);
+ val1 = dfvm_value_new(REGISTER);
+ val1->value.numeric = reg1;
+ val2 = dfvm_value_new(REGISTER);
+ val2->value.numeric = reg2;
+ insn->arg1 = val1;
+ insn->arg2 = val2;
+ dfw_append_insn(dfw, insn);
+
+ if (jmp1) {
+ jmp1->value.numeric = dfw->next_insn_id;
+ }
+
+ if (jmp2) {
+ jmp2->value.numeric = dfw->next_insn_id;
+ }
+}
+
+
+static void
+gen_test(dfwork_t *dfw, stnode_t *st_node)
+{
+ test_op_t st_op;
+ stnode_t *st_arg1, *st_arg2;
+ dfvm_value_t *val1;
+ dfvm_insn_t *insn;
+
+ header_field_info *hfinfo;
+
+ sttype_test_get(st_node, &st_op, &st_arg1, &st_arg2);
+
+ switch (st_op) {
+ case TEST_OP_UNINITIALIZED:
+ g_assert_not_reached();
+ break;
+
+ case TEST_OP_EXISTS:
+ val1 = dfvm_value_new(FIELD_ID);
+ hfinfo = stnode_data(st_arg1);
+ val1->value.numeric = hfinfo->id;
+ insn = dfvm_insn_new(CHECK_EXISTS);
+ insn->arg1 = val1;
+ dfw_append_insn(dfw, insn);
+ break;
+
+ case TEST_OP_NOT:
+ gencode(dfw, st_arg1);
+ insn = dfvm_insn_new(NOT);
+ dfw_append_insn(dfw, insn);
+ break;
+
+ case TEST_OP_AND:
+ gencode(dfw, st_arg1);
+
+ insn = dfvm_insn_new(IF_FALSE_GOTO);
+ val1 = dfvm_value_new(INSN_NUMBER);
+ insn->arg1 = val1;
+ dfw_append_insn(dfw, insn);
+
+ gencode(dfw, st_arg2);
+ val1->value.numeric = dfw->next_insn_id;
+ break;
+
+ case TEST_OP_OR:
+ gencode(dfw, st_arg1);
+
+ insn = dfvm_insn_new(IF_TRUE_GOTO);
+ val1 = dfvm_value_new(INSN_NUMBER);
+ insn->arg1 = val1;
+ dfw_append_insn(dfw, insn);
+
+ gencode(dfw, st_arg2);
+ val1->value.numeric = dfw->next_insn_id;
+ break;
+
+ case TEST_OP_EQ:
+ gen_relation(dfw, ANY_EQ, st_arg1, st_arg2);
+ break;
+
+ case TEST_OP_NE:
+ gen_relation(dfw, ANY_NE, st_arg1, st_arg2);
+ break;
+
+ case TEST_OP_GT:
+ gen_relation(dfw, ANY_GT, st_arg1, st_arg2);
+ break;
+
+ case TEST_OP_GE:
+ gen_relation(dfw, ANY_GE, st_arg1, st_arg2);
+ break;
+
+ case TEST_OP_LT:
+ gen_relation(dfw, ANY_LT, st_arg1, st_arg2);
+ break;
+
+ case TEST_OP_LE:
+ gen_relation(dfw, ANY_LE, st_arg1, st_arg2);
+ break;
+ }
+}
+
+static void
+gencode(dfwork_t *dfw, stnode_t *st_node)
+{
+ const char *name;
+
+ name = stnode_type_name(st_node);
+
+ switch (stnode_type_id(st_node)) {
+ case STTYPE_TEST:
+ gen_test(dfw, st_node);
+ break;
+ default:
+ g_assert_not_reached();
+ }
+}
+
+
+void
+dfw_gencode(dfwork_t *dfw)
+{
+ dfw->insns = g_ptr_array_new();
+ dfw->loaded_fields = g_hash_table_new(g_direct_hash, g_direct_equal);
+ gencode(dfw, dfw->st_root);
+ dfw_append_insn(dfw, dfvm_insn_new(RETURN));
+}
+
diff --git a/epan/dfilter/gencode.h b/epan/dfilter/gencode.h
new file mode 100644
index 0000000000..db56b9082c
--- /dev/null
+++ b/epan/dfilter/gencode.h
@@ -0,0 +1,7 @@
+#ifndef GENCODE_H
+#define GENCODE_H
+
+void
+dfw_gencode(dfwork_t *dfw);
+
+#endif
diff --git a/epan/dfilter/glib-util.c b/epan/dfilter/glib-util.c
new file mode 100644
index 0000000000..9e63fab4f3
--- /dev/null
+++ b/epan/dfilter/glib-util.c
@@ -0,0 +1,47 @@
+/* $Id: glib-util.c,v 1.1 2001/02/01 20:21:18 gram Exp $ */
+
+#include <string.h>
+#include <glib.h>
+
+
+#include <glib-util.h>
+
+char*
+g_substrdup(const char *s, int start, int len)
+{
+ int s_len, abs_start, abs_len;
+ char *newstring;
+
+
+ s_len = strlen(s);
+
+ if (start < 0) {
+ abs_start = s_len + start;
+ if (abs_start < 0) {
+ return NULL;
+ }
+ }
+ else {
+ abs_start = start;
+ }
+
+ if (len < 0) {
+ abs_len = s_len + len + 1 - abs_start;
+ if (abs_len < 0) {
+ return NULL;
+ }
+ }
+ else {
+ abs_len = len;
+ }
+
+
+ if (abs_start + abs_len > s_len) {
+ return NULL;
+ }
+
+ newstring = g_strndup(s + abs_start, abs_len + 1);
+ newstring[abs_len] = 0;
+
+ return newstring;
+}
diff --git a/epan/dfilter/glib-util.h b/epan/dfilter/glib-util.h
new file mode 100644
index 0000000000..90a81f7eed
--- /dev/null
+++ b/epan/dfilter/glib-util.h
@@ -0,0 +1,4 @@
+/* $Id: glib-util.h,v 1.1 2001/02/01 20:21:18 gram Exp $ */
+
+char*
+g_substrdup(const char *s, int start, int len);
diff --git a/epan/dfilter/grammar.lemon b/epan/dfilter/grammar.lemon
new file mode 100644
index 0000000000..8072458ab7
--- /dev/null
+++ b/epan/dfilter/grammar.lemon
@@ -0,0 +1,185 @@
+/* $Id: grammar.lemon,v 1.1 2001/02/01 20:21:18 gram Exp $ */
+
+%include {
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "dfilter-int.h"
+#include "syntax-tree.h"
+#include "sttype-range.h"
+#include "sttype-test.h"
+
+/*extern char *df_text;*/
+
+/* End of C code */
+}
+
+/* Parser Information */
+%name Dfilter
+%token_prefix TOKEN_
+%extra_argument {dfwork_t *dfw}
+
+/* Terminal and Non-Terminal types and destructors */
+%token_type {stnode_t*}
+%token_destructor {stnode_free($$);}
+
+%type sentence {stnode_t*}
+%destructor sentence {stnode_free($$);}
+
+%type expr {stnode_t*}
+%destructor expr {stnode_free($$);}
+
+%type entity {stnode_t*}
+%destructor entity {stnode_free($$);}
+
+%type relation_test {stnode_t*}
+%destructor relation_test {stnode_free($$);}
+
+%type logical_test {stnode_t*}
+%destructor logical_test {stnode_free($$);}
+
+%type rel_op2 {test_op_t}
+
+%type range {stnode_t*}
+%destructor range {stnode_free($$);}
+
+/* This is called as soon as a syntax error happens. After that,
+any "error" symbols are shifted, if possible. */
+%syntax_error {
+
+ header_field_info *hfinfo;
+
+ if (!TOKEN) {
+ dfilter_fail("Unexpected end of filter string.");
+ return;
+ }
+
+ switch(stnode_type_id(TOKEN)) {
+ case STTYPE_UNINITIALIZED:
+ dfilter_fail("Syntax error.");
+ break;
+ case STTYPE_TEST:
+ dfilter_fail("Syntax error, TEST.");
+ break;
+ case STTYPE_STRING:
+ dfilter_fail("The string \"%s\" was unexpected in this context.",
+ stnode_data(TOKEN));
+ break;
+ case STTYPE_FIELD:
+ hfinfo = stnode_data(TOKEN);
+ dfilter_fail("Syntax error near \"%s\".", hfinfo->abbrev);
+ break;
+
+ /* These aren't handed to use as terminal tokens from
+ the scanner, so was can assert that we'll never
+ see them here. */
+ case STTYPE_NUM_TYPES:
+ case STTYPE_RANGE:
+ case STTYPE_FVALUE:
+ g_assert_not_reached();
+ break;
+ }
+}
+
+/* When a parse fails, mark an error. This occurs after
+the above syntax_error code and after the parser fails to
+use error recovery, shifting an "error" symbol and successfully
+shifting 3 more symbols. */
+%parse_failure {
+ dfw->syntax_error = TRUE;
+}
+
+/* ----------------- The grammar -------------- */
+
+/* Associativity */
+%left TEST_AND.
+%left TEST_OR.
+%nonassoc TEST_EQ TEST_NE TEST_LT TEST_LE TEST_GT TEST_GE.
+%right TEST_NOT.
+
+/* Top-level targets */
+sentence ::= expr(X). { dfw->st_root = X; }
+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).
+{
+ T = stnode_new(STTYPE_TEST, NULL);
+ sttype_test_set2(T, TEST_OP_AND, E, F);
+}
+
+logical_test(T) ::= expr(E) TEST_OR expr(F).
+{
+ T = stnode_new(STTYPE_TEST, NULL);
+ sttype_test_set2(T, TEST_OP_OR, E, F);
+}
+
+logical_test(T) ::= TEST_NOT expr(E).
+{
+ T = stnode_new(STTYPE_TEST, NULL);
+ sttype_test_set1(T, TEST_OP_NOT, E);
+}
+
+logical_test(T) ::= FIELD(F).
+{
+ T = stnode_new(STTYPE_TEST, NULL);
+ sttype_test_set1(T, TEST_OP_EXISTS, F);
+}
+
+
+
+/* Entities, or things that can be compared/tested/checked */
+entity(E) ::= FIELD(F). { E = F; }
+entity(E) ::= STRING(S). { E = S; }
+entity(E) ::= range(R). { E = R; }
+
+range(R) ::= FIELD(F) LBRACKET STRING(X) COLON STRING(Y) RBRACKET.
+{
+ R = stnode_new(STTYPE_RANGE, NULL);
+ sttype_range_set(R, F, X, Y);
+}
+
+range(R) ::= FIELD(F) LBRACKET STRING(X) COLON RBRACKET.
+{
+ R = stnode_new(STTYPE_RANGE, NULL);
+ sttype_range_set(R, F, X, NULL);
+}
+
+range(R) ::= FIELD(F) LBRACKET COLON STRING(Y) RBRACKET.
+{
+ R = stnode_new(STTYPE_RANGE, NULL);
+ sttype_range_set(R, F, NULL, Y);
+}
+
+range(R) ::= FIELD(F) LBRACKET STRING(Y) RBRACKET.
+{
+ R = stnode_new(STTYPE_RANGE, NULL);
+ sttype_range_set1(R, F, Y);
+}
+
+/* Relational tests */
+relation_test(T) ::= entity(E) rel_op2(O) entity(F).
+{
+ T = stnode_new(STTYPE_TEST, NULL);
+ sttype_test_set2(T, O, E, F);
+}
+
+rel_op2(O) ::= TEST_EQ. { O = TEST_OP_EQ; }
+rel_op2(O) ::= TEST_NE. { O = TEST_OP_NE; }
+rel_op2(O) ::= TEST_GT. { O = TEST_OP_GT; }
+rel_op2(O) ::= TEST_GE. { O = TEST_OP_GE; }
+rel_op2(O) ::= TEST_LT. { O = TEST_OP_LT; }
+rel_op2(O) ::= TEST_LE. { O = TEST_OP_LE; }
+
+
+
diff --git a/epan/dfilter/scanner.l b/epan/dfilter/scanner.l
new file mode 100644
index 0000000000..a10c9fd77f
--- /dev/null
+++ b/epan/dfilter/scanner.l
@@ -0,0 +1,157 @@
+%{
+/* scanner.l
+ * Scanner for Ethereal's dfilter language
+ *
+ * $Id: scanner.l,v 1.1 2001/02/01 20:21:18 gram Exp $
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "glib-util.h"
+#include "dfilter-int.h"
+#include "syntax-tree.h"
+#include "grammar.h"
+
+#define LVAL df_lval
+#define LVAL_TYPE stnode_t*
+#define LVAL_INIT_VAL NULL
+#define MODNAME df
+
+#include <lemonflex-head.inc>
+
+/*#undef YY_NO_UNPUT*/
+
+int set_lval(int token, gpointer data);
+int simple(int token);
+
+%}
+
+%x RANGE
+
+BWCHARS [[:alnum:]\[\]\-_.+!@#%^&*=/:]
+INITVAR [_A-Za-z]
+VARCHARS [[:alnum:]_]
+
+
+%%
+
+[[:blank:]\n]+ /* ignore whitespace */
+
+
+
+"(" return simple(TOKEN_LPAREN);
+")" return simple(TOKEN_RPAREN);
+
+"==" return simple(TOKEN_TEST_EQ);
+"eq" return simple(TOKEN_TEST_EQ);
+"!=" return simple(TOKEN_TEST_NE);
+"ne" return simple(TOKEN_TEST_NE);
+">" return simple(TOKEN_TEST_GT);
+"gt" return simple(TOKEN_TEST_GT);
+">=" return simple(TOKEN_TEST_GE);
+"ge" return simple(TOKEN_TEST_GE);
+"<" return simple(TOKEN_TEST_LT);
+"lt" return simple(TOKEN_TEST_LT);
+"<=" return simple(TOKEN_TEST_LE);
+"le" return simple(TOKEN_TEST_LE);
+
+"!" return simple(TOKEN_TEST_NOT);
+"not" return simple(TOKEN_TEST_NOT);
+"&&" return simple(TOKEN_TEST_AND);
+"and" return simple(TOKEN_TEST_AND);
+"||" return simple(TOKEN_TEST_OR);
+"or" return simple(TOKEN_TEST_OR);
+
+
+"[" {
+ BEGIN(RANGE);
+ return simple(TOKEN_LBRACKET);
+}
+
+<RANGE>[+-]?[[:digit:]]+ {
+ return set_lval(TOKEN_STRING, g_strdup(yytext));
+}
+<RANGE>[+-]?0x[[:xdigit:]]+ {
+ return set_lval(TOKEN_STRING, g_strdup(yytext));
+}
+<RANGE>":" return simple(TOKEN_COLON);
+
+<RANGE>"]" {
+ BEGIN(INITIAL);
+ return simple(TOKEN_RBRACKET);
+}
+
+
+\"[^"]*\" {
+ return set_lval(TOKEN_STRING, g_substrdup(yytext, 1, -2));
+}
+
+
+
+[[:alnum:]_.:]+ {
+ /* Is it a field name? */
+ header_field_info *hfinfo;
+
+ hfinfo = dfilter_lookup_token(yytext);
+ if (hfinfo) {
+ /* Yes, it's a field name */
+ return set_lval(TOKEN_FIELD, hfinfo);
+ }
+ else {
+ /* No, so treat it as a string */
+ return set_lval(TOKEN_STRING, g_strdup(yytext));
+ }
+}
+
+
+
+%%
+
+int
+simple(int token)
+{
+ switch (token) {
+ case TOKEN_LPAREN:
+ case TOKEN_RPAREN:
+ case TOKEN_LBRACKET:
+ case TOKEN_RBRACKET:
+ case TOKEN_COLON:
+ case TOKEN_TEST_EQ:
+ case TOKEN_TEST_NE:
+ case TOKEN_TEST_GT:
+ case TOKEN_TEST_GE:
+ case TOKEN_TEST_LT:
+ case TOKEN_TEST_LE:
+ case TOKEN_TEST_NOT:
+ case TOKEN_TEST_AND:
+ case TOKEN_TEST_OR:
+ break;
+ default:
+ g_assert_not_reached();
+ }
+ return token;
+}
+
+int
+set_lval(int token, gpointer data)
+{
+ sttype_id_t type_id = STTYPE_UNINITIALIZED;
+
+ switch (token) {
+ case TOKEN_STRING:
+ type_id = STTYPE_STRING;
+ break;
+ case TOKEN_FIELD:
+ type_id = STTYPE_FIELD;
+ break;
+ default:
+ g_assert_not_reached();
+ }
+
+ stnode_init(df_lval, type_id, data);
+ return token;
+}
+
+#include <lemonflex-tail.inc>
diff --git a/epan/dfilter/semcheck.c b/epan/dfilter/semcheck.c
new file mode 100644
index 0000000000..24b1b93f80
--- /dev/null
+++ b/epan/dfilter/semcheck.c
@@ -0,0 +1,472 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+
+#include "dfilter-int.h"
+#include "syntax-tree.h"
+#include "sttype-range.h"
+#include "sttype-test.h"
+
+#include "exceptions.h"
+
+static void
+semcheck(dfwork_t *dfw, stnode_t *st_node);
+
+typedef gboolean (*FtypeCanFunc)(enum ftenum);
+
+/* Compares to ftenum_t's and decides if they're
+ * compatible or not (if they're the same basic type) */
+static gboolean
+compatible_ftypes(ftenum_t a, ftenum_t b)
+{
+ switch (a) {
+ case FT_NONE:
+ case FT_PROTOCOL:
+ case FT_DOUBLE:
+ case FT_ABSOLUTE_TIME:
+ case FT_RELATIVE_TIME:
+ case FT_IPv4:
+ case FT_IPv6:
+ case FT_IPXNET:
+ return a == b;
+
+ case FT_ETHER:
+ case FT_BYTES:
+ return (b == FT_ETHER || b == FT_BYTES);
+
+ case FT_BOOLEAN:
+ case FT_UINT8:
+ case FT_UINT16:
+ case FT_UINT24:
+ case FT_UINT32:
+ case FT_INT8:
+ case FT_INT16:
+ case FT_INT24:
+ case FT_INT32:
+ switch (b) {
+ case FT_BOOLEAN:
+ case FT_UINT8:
+ case FT_UINT16:
+ case FT_UINT24:
+ case FT_UINT32:
+ case FT_INT8:
+ case FT_INT16:
+ case FT_INT24:
+ case FT_INT32:
+ return TRUE;
+ default:
+ return FALSE;
+ }
+
+ case FT_STRING:
+ case FT_STRINGZ:
+ case FT_UINT_STRING:
+ switch (b) {
+ case FT_STRING:
+ case FT_STRINGZ:
+ case FT_UINT_STRING:
+ return TRUE;
+ default:
+ return FALSE;
+ }
+
+ case FT_NUM_TYPES:
+ g_assert_not_reached();
+ }
+
+ g_assert_not_reached();
+ return FALSE;
+}
+
+/* Creates a FT_UINT32 fvalue with a given value. */
+static fvalue_t*
+mk_uint32_fvalue(guint32 val)
+{
+ fvalue_t *fv;
+
+ fv = fvalue_new(FT_UINT32);
+ fvalue_set_integer(fv, val);
+
+ return fv;
+}
+
+
+/* Try to make an fvalue from a string using a value_string or true_false_string.
+ * This works only for ftypes that are integers. Returns the created fvalue_t*
+ * or NULL if impossible. */
+static fvalue_t*
+mk_fvalue_from_val_string(header_field_info *hfinfo, char *s)
+{
+ static true_false_string default_tf = { "True", "False" };
+ true_false_string *tf = &default_tf;
+ value_string *vals;
+
+ /* Early return? */
+ switch(hfinfo->type) {
+ case FT_NONE:
+ case FT_PROTOCOL:
+ case FT_DOUBLE:
+ case FT_ABSOLUTE_TIME:
+ case FT_RELATIVE_TIME:
+ case FT_IPv4:
+ case FT_IPv6:
+ case FT_IPXNET:
+ case FT_ETHER:
+ case FT_BYTES:
+ case FT_STRING:
+ case FT_STRINGZ:
+ case FT_UINT_STRING:
+ return FALSE;
+
+ case FT_BOOLEAN:
+ case FT_UINT8:
+ case FT_UINT16:
+ case FT_UINT24:
+ case FT_UINT32:
+ case FT_INT8:
+ case FT_INT16:
+ case FT_INT24:
+ case FT_INT32:
+ break;
+
+ case FT_NUM_TYPES:
+ g_assert_not_reached();
+ }
+
+ /* Reset the dfilter error message, since *something* interesting
+ * will happen, and the error message will be more interesting than
+ * any error message I happen to have now. */
+ dfilter_error_msg = NULL;
+
+ /* TRUE/FALSE *always* exist for FT_BOOLEAN. */
+ if (hfinfo->type == FT_BOOLEAN) {
+ if (hfinfo->strings) {
+ tf = hfinfo->strings;
+ }
+
+ if (strcasecmp(s, tf->true_string) == 0) {
+ return mk_uint32_fvalue(TRUE);
+ }
+ else if (strcasecmp(s, tf->false_string) == 0) {
+ return mk_uint32_fvalue(FALSE);
+ }
+ else {
+ dfilter_fail("\"%s\" cannot be found among the possible values for %s.",
+ s, hfinfo->abbrev);
+ return NULL;
+ }
+ }
+
+ /* Do val_strings exist? */
+ if (!hfinfo->strings) {
+ dfilter_fail("%s cannot accept strings as values.",
+ hfinfo->abbrev);
+ return FALSE;
+ }
+
+ vals = hfinfo->strings;
+ while (vals->strptr != NULL) {
+ if (strcasecmp(s, vals->strptr) == 0) {
+ return mk_uint32_fvalue(vals->value);
+ }
+ vals++;
+ }
+ dfilter_fail("\"%s\" cannot be found among the possible values for %s.",
+ s, hfinfo->abbrev);
+ return FALSE;
+}
+
+
+static gboolean
+is_bytes_type(enum ftenum type)
+{
+ switch(type) {
+ case FT_ETHER:
+ case FT_BYTES:
+ case FT_IPv6:
+ return TRUE;
+
+ case FT_NONE:
+ case FT_PROTOCOL:
+ case FT_DOUBLE:
+ case FT_ABSOLUTE_TIME:
+ case FT_RELATIVE_TIME:
+ case FT_IPv4:
+ case FT_IPXNET:
+ case FT_STRING:
+ case FT_STRINGZ:
+ case FT_UINT_STRING:
+ case FT_BOOLEAN:
+ case FT_UINT8:
+ case FT_UINT16:
+ case FT_UINT24:
+ case FT_UINT32:
+ case FT_INT8:
+ case FT_INT16:
+ case FT_INT24:
+ case FT_INT32:
+ return FALSE;
+
+ case FT_NUM_TYPES:
+ g_assert_not_reached();
+ }
+
+ g_assert_not_reached();
+ return FALSE;
+}
+
+/* This could really be split up... it's too big. */
+static void
+check_relation(dfwork_t *dfw, FtypeCanFunc can_func, stnode_t *st_node,
+ stnode_t *st_arg1, stnode_t *st_arg2)
+{
+ stnode_t *new_st;
+ sttype_id_t type1, type2;
+ header_field_info *hfinfo1, *hfinfo2;
+ ftenum_t ftype1, ftype2;
+ fvalue_t *fvalue;
+ char *s;
+
+ type1 = stnode_type_id(st_arg1);
+ type2 = stnode_type_id(st_arg2);
+ if (type1 == STTYPE_FIELD) {
+ hfinfo1 = stnode_data(st_arg1);
+ ftype1 = hfinfo1->type;
+
+ if (!can_func(ftype1)) {
+ dfilter_fail("%s (type=%s) cannot participate in specified comparison.",
+ hfinfo1->abbrev, ftype_pretty_name(ftype1));
+ THROW(TypeError);
+ }
+
+
+ if (type2 == STTYPE_FIELD) {
+ hfinfo2 = stnode_data(st_arg2);
+ ftype2 = hfinfo2->type;
+
+ if (!compatible_ftypes(ftype1, ftype2)) {
+ dfilter_fail("%s and %s are not of compatible types.",
+ hfinfo1->abbrev, 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);
+ fvalue = fvalue_from_string(ftype1, s, dfilter_fail);
+ if (!fvalue) {
+ /* check value_string */
+ fvalue = mk_fvalue_from_val_string(hfinfo1, s);
+ 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) {
+ if (!is_bytes_type(ftype1)) {
+ if (!ftype_can_slice(ftype1)) {
+ dfilter_fail("\"%s\" is a %s and cannot be converted into a sequence of bytes.",
+ hfinfo1->abbrev,
+ ftype_pretty_name(ftype1));
+ THROW(TypeError);
+ }
+
+ /* Convert entire field to bytes */
+ new_st = stnode_new(STTYPE_RANGE, NULL);
+
+ /* st_arg1 is freed in this step */
+ sttype_range_set(new_st, st_arg1, NULL, NULL);
+
+ sttype_test_set2_args(st_node, new_st, st_arg2);
+ }
+ }
+ else {
+ g_assert_not_reached();
+ }
+ }
+ else if (type1 == STTYPE_STRING) {
+
+ if (type2 == STTYPE_FIELD) {
+ hfinfo2 = stnode_data(st_arg2);
+ ftype2 = hfinfo2->type;
+
+ s = stnode_data(st_arg1);
+ fvalue = fvalue_from_string(ftype2, s, dfilter_fail);
+ if (!fvalue) {
+ /* check value_string */
+ fvalue = mk_fvalue_from_val_string(hfinfo2, s);
+ if (!fvalue) {
+ THROW(TypeError);
+ }
+ }
+
+ new_st = stnode_new(STTYPE_FVALUE, fvalue);
+ sttype_test_set2_args(st_node, new_st, st_arg2);
+ stnode_free(st_arg1);
+ }
+ else if (type2 == STTYPE_STRING) {
+ /* Well now that's silly... */
+ dfilter_fail("Neither \"%s\" nor \"%s\" are field or protocol names.",
+ stnode_data(st_arg1),
+ stnode_data(st_arg2));
+ THROW(TypeError);
+ }
+ else if (type2 == STTYPE_RANGE) {
+ s = stnode_data(st_arg1);
+ fvalue = fvalue_from_string(FT_BYTES, s, dfilter_fail);
+ if (!fvalue) {
+ THROW(TypeError);
+ }
+ new_st = stnode_new(STTYPE_FVALUE, fvalue);
+ sttype_test_set2_args(st_node, new_st, st_arg2);
+ stnode_free(st_arg1);
+ }
+ else {
+ g_assert_not_reached();
+ }
+ }
+ else if (type1 == STTYPE_RANGE) {
+ hfinfo1 = sttype_range_hfinfo(st_arg1);
+ ftype1 = hfinfo1->type;
+
+ if (!ftype_can_slice(ftype1)) {
+ dfilter_fail("\"%s\" is a %s and cannot be sliced into a sequence of bytes.",
+ hfinfo1->abbrev, ftype_pretty_name(ftype1));
+ THROW(TypeError);
+ }
+
+
+ if (type2 == STTYPE_FIELD) {
+ hfinfo2 = sttype_range_hfinfo(st_arg2);
+ ftype2 = hfinfo2->type;
+
+ if (!is_bytes_type(ftype2)) {
+ if (!ftype_can_slice(ftype2)) {
+ dfilter_fail("\"%s\" is a %s and cannot be converted into a sequence of bytes.",
+ hfinfo2->abbrev,
+ ftype_pretty_name(ftype2));
+ THROW(TypeError);
+ }
+
+ /* Convert entire field to bytes */
+ new_st = stnode_new(STTYPE_RANGE, NULL);
+
+ /* st_arg2 is freed in this step */
+ sttype_range_set(new_st, st_arg2, NULL, NULL);
+
+ sttype_test_set2_args(st_node, st_arg1, new_st);
+ }
+ }
+ else if (type2 == STTYPE_STRING) {
+ s = stnode_data(st_arg2);
+ fvalue = fvalue_from_string(FT_BYTES, 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_RANGE) {
+ /* XXX - check lengths of both ranges */
+ }
+ else {
+ g_assert_not_reached();
+ }
+ }
+ else {
+ g_assert_not_reached();
+ }
+}
+
+static void
+check_test(dfwork_t *dfw, stnode_t *st_node)
+{
+ test_op_t st_op;
+ stnode_t *st_arg1, *st_arg2;
+
+ sttype_test_get(st_node, &st_op, &st_arg1, &st_arg2);
+
+ switch (st_op) {
+ case TEST_OP_UNINITIALIZED:
+ g_assert_not_reached();
+ break;
+
+ case TEST_OP_EXISTS:
+ /* nothing */
+ break;
+
+ case TEST_OP_NOT:
+ semcheck(dfw, st_arg1);
+ break;
+
+ case TEST_OP_AND:
+ case TEST_OP_OR:
+ semcheck(dfw, st_arg1);
+ semcheck(dfw, st_arg2);
+ break;
+
+ case TEST_OP_EQ:
+ check_relation(dfw, ftype_can_eq, st_node, st_arg1, st_arg2);
+ break;
+ case TEST_OP_NE:
+ check_relation(dfw, ftype_can_ne, st_node, st_arg1, st_arg2);
+ break;
+ case TEST_OP_GT:
+ check_relation(dfw, ftype_can_gt, st_node, st_arg1, st_arg2);
+ break;
+ case TEST_OP_GE:
+ check_relation(dfw, ftype_can_ge, st_node, st_arg1, st_arg2);
+ break;
+ case TEST_OP_LT:
+ check_relation(dfw, ftype_can_lt, st_node, st_arg1, st_arg2);
+ break;
+ case TEST_OP_LE:
+ check_relation(dfw, ftype_can_le, st_node, st_arg1, st_arg2);
+ break;
+ }
+}
+
+
+static void
+semcheck(dfwork_t *dfw, stnode_t *st_node)
+{
+ const char *name;
+
+ name = stnode_type_name(st_node);
+
+ switch (stnode_type_id(st_node)) {
+ case STTYPE_TEST:
+ check_test(dfw, st_node);
+ break;
+ default:
+ g_assert_not_reached();
+ }
+}
+
+
+gboolean
+dfw_semcheck(dfwork_t *dfw)
+{
+ TRY {
+ semcheck(dfw, dfw->st_root);
+ }
+ CATCH(TypeError) {
+ return FALSE;
+ }
+ ENDTRY;
+
+ return TRUE;
+}
diff --git a/epan/dfilter/semcheck.h b/epan/dfilter/semcheck.h
new file mode 100644
index 0000000000..54f795dfe4
--- /dev/null
+++ b/epan/dfilter/semcheck.h
@@ -0,0 +1,10 @@
+#ifndef SEMCHECK_H
+#define SEMCHECK_H
+
+
+
+gboolean
+dfw_semcheck(dfwork_t *dfw);
+
+
+#endif
diff --git a/epan/dfilter/sttype-pointer.c b/epan/dfilter/sttype-pointer.c
new file mode 100644
index 0000000000..64a49658f2
--- /dev/null
+++ b/epan/dfilter/sttype-pointer.c
@@ -0,0 +1,28 @@
+/* $Id: sttype-pointer.c,v 1.1 2001/02/01 20:21:18 gram Exp $ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "ftypes/ftypes.h"
+#include "syntax-tree.h"
+
+void
+sttype_register_pointer(void)
+{
+ static sttype_t field_type = {
+ STTYPE_FIELD,
+ "FIELD",
+ NULL,
+ NULL,
+ };
+ static sttype_t fvalue_type = {
+ STTYPE_FVALUE,
+ "FVALUE",
+ NULL,
+ NULL,
+ };
+
+ sttype_register(&field_type);
+ sttype_register(&fvalue_type);
+}
diff --git a/epan/dfilter/sttype-range.c b/epan/dfilter/sttype-range.c
new file mode 100644
index 0000000000..12bada4cc4
--- /dev/null
+++ b/epan/dfilter/sttype-range.c
@@ -0,0 +1,174 @@
+/* $Id: sttype-range.c,v 1.1 2001/02/01 20:21:18 gram Exp $ */
+
+/* The ideas in this code came from Ed Warnicke's original implementation
+ * of dranges for the old display filter code (Ethereal 0.8.15 and before).
+ * The code is different, but definitely inspired by his code.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <errno.h>
+#include "proto.h"
+#include "sttype-range.h"
+
+typedef struct {
+ guint32 magic;
+ header_field_info *hfinfo;
+ gint start;
+ gint end;
+ char *start_error;
+ char *end_error;
+} range_t;
+
+#define RANGE_MAGIC 0xec0990ce
+
+static gpointer
+range_new(gpointer junk)
+{
+ range_t *range;
+
+ g_assert(junk == NULL);
+
+ range = g_new(range_t, 1);
+
+ range->magic = RANGE_MAGIC;
+ range->hfinfo = NULL;
+ range->start = 0;
+ range->end = -1;
+ range->start_error = NULL;
+ range->end_error = NULL;
+
+ return (gpointer) range;
+}
+
+static void
+range_free(gpointer value)
+{
+ range_t *range = value;
+ assert_magic(range, RANGE_MAGIC);
+
+ if (range->start_error)
+ g_free(range->start_error);
+ if (range->end_error)
+ g_free(range->end_error);
+
+ g_free(range);
+}
+
+static gint
+string_to_gint(char *s, gboolean *success)
+{
+ char *endptr;
+ gint val;
+
+ *success = TRUE;
+ val = strtol(s, &endptr, 0);
+
+ if (endptr == s || *endptr != '\0') {
+ *success = FALSE;
+ }
+ else if (errno == ERANGE) {
+ *success = FALSE;
+ }
+
+ return val;
+}
+
+static void
+range_set(stnode_t *node, stnode_t *field, char *start, char *end)
+{
+ range_t *range;
+ gboolean success;
+
+ range = stnode_data(node);
+ assert_magic(range, RANGE_MAGIC);
+
+ range->hfinfo = stnode_data(field);
+ stnode_free(field);
+
+ if (start) {
+ range->start = string_to_gint(start, &success);
+ if (!success) {
+ /* Save the error-causing string for later reporting */
+ range->start_error = g_strdup(start);
+ }
+ }
+ else {
+ range->start = 0;
+ }
+
+ if (end) {
+ range->end = string_to_gint(end, &success);
+
+ if (!success) {
+ /* Save the error-causing string for later reporting */
+ range->end_error = g_strdup(end);
+ }
+ }
+ else {
+ range->end = G_MAXINT;
+ }
+}
+
+void
+sttype_range_set(stnode_t *node, stnode_t *field, stnode_t *start, stnode_t *end)
+{
+ char *start_str, *end_str;
+
+ if (start) {
+ start_str = stnode_data(start);
+ }
+ else {
+ start_str = NULL;
+ }
+
+ if (end) {
+ end_str = stnode_data(end);
+ }
+ else {
+ end_str = NULL;
+ }
+
+ range_set(node, field, start_str, end_str);
+
+ if (start)
+ stnode_free(start);
+ if (end)
+ stnode_free(end);
+}
+
+void
+sttype_range_set1(stnode_t *node, stnode_t *field, stnode_t *offset)
+{
+ char *offset_str;
+
+ g_assert(offset);
+
+ offset_str = stnode_data(offset);
+ range_set(node, field, offset_str, "1");
+ stnode_free(offset);
+}
+
+
+STTYPE_ACCESSOR(header_field_info*, range, hfinfo, RANGE_MAGIC)
+STTYPE_ACCESSOR(gint, range, start, RANGE_MAGIC)
+STTYPE_ACCESSOR(gint, range, end, RANGE_MAGIC)
+STTYPE_ACCESSOR(char*, range, start_error, RANGE_MAGIC)
+STTYPE_ACCESSOR(char*, range, end_error, RANGE_MAGIC)
+
+
+void
+sttype_register_range(void)
+{
+ static sttype_t range_type = {
+ STTYPE_RANGE,
+ "RANGE",
+ range_new,
+ range_free,
+ };
+
+ sttype_register(&range_type);
+}
diff --git a/epan/dfilter/sttype-range.h b/epan/dfilter/sttype-range.h
new file mode 100644
index 0000000000..aff39c84b5
--- /dev/null
+++ b/epan/dfilter/sttype-range.h
@@ -0,0 +1,20 @@
+#ifndef STTYPE_RANGE_H
+#define STTYPE_RANGE_H
+
+#include "syntax-tree.h"
+
+STTYPE_ACCESSOR_PROTOTYPE(header_field_info*, range, hfinfo)
+STTYPE_ACCESSOR_PROTOTYPE(gint, range, start)
+STTYPE_ACCESSOR_PROTOTYPE(gint, range, end)
+STTYPE_ACCESSOR_PROTOTYPE(char*, range, start_error)
+STTYPE_ACCESSOR_PROTOTYPE(char*, range, end_error)
+
+/* Set a range, [x:y], [:y], [x:] */
+void
+sttype_range_set(stnode_t *node, stnode_t *field, stnode_t *start, stnode_t *end);
+
+/* Set a single-byte lookup, [x] */
+void
+sttype_range_set1(stnode_t *node, stnode_t *field, stnode_t *offset);
+
+#endif
diff --git a/epan/dfilter/sttype-string.c b/epan/dfilter/sttype-string.c
new file mode 100644
index 0000000000..c19797844d
--- /dev/null
+++ b/epan/dfilter/sttype-string.c
@@ -0,0 +1,29 @@
+/* $Id: sttype-string.c,v 1.1 2001/02/01 20:21:18 gram Exp $ */
+
+#include "syntax-tree.h"
+
+static gpointer
+string_new(gpointer string)
+{
+ return (gpointer) g_strdup((char*) string);
+}
+
+static void
+string_free(gpointer value)
+{
+ g_free(value);
+}
+
+
+void
+sttype_register_string(void)
+{
+ static sttype_t string_type = {
+ STTYPE_STRING,
+ "STRING",
+ string_new,
+ string_free,
+ };
+
+ sttype_register(&string_type);
+}
diff --git a/epan/dfilter/sttype-test.c b/epan/dfilter/sttype-test.c
new file mode 100644
index 0000000000..90b07048e0
--- /dev/null
+++ b/epan/dfilter/sttype-test.c
@@ -0,0 +1,144 @@
+/* $Id: sttype-test.c,v 1.1 2001/02/01 20:21:18 gram Exp $ */
+
+#include "syntax-tree.h"
+#include "sttype-test.h"
+
+typedef struct {
+ guint32 magic;
+ test_op_t op;
+ stnode_t *val1;
+ stnode_t *val2;
+} test_t;
+
+#define TEST_MAGIC 0xab9009ba
+
+static gpointer
+test_new(gpointer junk)
+{
+ test_t *test;
+
+ g_assert(junk == NULL);
+
+ test = g_new(test_t, 1);
+
+ test->magic = TEST_MAGIC;
+ test->op = TEST_OP_UNINITIALIZED;
+ test->val1 = NULL;
+ test->val2 = NULL;
+
+ return (gpointer) test;
+}
+
+static void
+test_free(gpointer value)
+{
+ test_t *test = value;
+ assert_magic(test, TEST_MAGIC);
+
+ if (test->val1)
+ stnode_free(test->val1);
+ if (test->val2)
+ stnode_free(test->val2);
+
+ g_free(test);
+}
+
+static int
+num_operands(test_op_t op)
+{
+ switch(op) {
+ case TEST_OP_UNINITIALIZED:
+ g_assert_not_reached();
+ case TEST_OP_EXISTS:
+ return 1;
+ case TEST_OP_NOT:
+ return 1;
+ case TEST_OP_AND:
+ return 2;
+ case TEST_OP_OR:
+ return 2;
+ case TEST_OP_EQ:
+ return 2;
+ case TEST_OP_NE:
+ return 2;
+ case TEST_OP_GT:
+ return 2;
+ case TEST_OP_GE:
+ return 2;
+ case TEST_OP_LT:
+ return 2;
+ case TEST_OP_LE:
+ return 2;
+ }
+ g_assert_not_reached();
+ return -1;
+}
+
+
+void
+sttype_test_set1(stnode_t *node, test_op_t op, stnode_t *val1)
+{
+ test_t *test;
+
+ test = stnode_data(node);
+ assert_magic(test, TEST_MAGIC);
+
+ g_assert(num_operands(op) == 1);
+ test->op = op;
+ test->val1 = val1;
+}
+
+void
+sttype_test_set2(stnode_t *node, test_op_t op, stnode_t *val1, stnode_t *val2)
+{
+ test_t *test;
+
+ test = stnode_data(node);
+ assert_magic(test, TEST_MAGIC);
+
+ g_assert(num_operands(op) == 2);
+ test->op = op;
+ test->val1 = val1;
+ test->val2 = val2;
+}
+
+void
+sttype_test_set2_args(stnode_t *node, stnode_t *val1, stnode_t *val2)
+{
+ test_t *test;
+
+ test = stnode_data(node);
+ assert_magic(test, TEST_MAGIC);
+
+ if (num_operands(test->op) == 1) {
+ g_assert(val2 == NULL);
+ }
+ test->val1 = val1;
+ test->val2 = val2;
+}
+
+void
+sttype_test_get(stnode_t *node, test_op_t *p_op, stnode_t **p_val1, stnode_t **p_val2)
+{
+ test_t *test;
+
+ test = stnode_data(node);
+ assert_magic(test, TEST_MAGIC);
+
+ *p_op = test->op;
+ *p_val1 = test->val1;
+ *p_val2 = test->val2;
+}
+
+void
+sttype_register_test(void)
+{
+ static sttype_t test_type = {
+ STTYPE_TEST,
+ "TEST",
+ test_new,
+ test_free,
+ };
+
+ sttype_register(&test_type);
+}
diff --git a/epan/dfilter/sttype-test.h b/epan/dfilter/sttype-test.h
new file mode 100644
index 0000000000..69765df9e3
--- /dev/null
+++ b/epan/dfilter/sttype-test.h
@@ -0,0 +1,30 @@
+#ifndef STTYPE_TEST_H
+#define STTYPE_TEST_H
+
+typedef enum {
+ TEST_OP_UNINITIALIZED,
+ TEST_OP_EXISTS,
+ TEST_OP_NOT,
+ TEST_OP_AND,
+ TEST_OP_OR,
+ TEST_OP_EQ,
+ TEST_OP_NE,
+ TEST_OP_GT,
+ TEST_OP_GE,
+ TEST_OP_LT,
+ TEST_OP_LE
+} test_op_t;
+
+void
+sttype_test_set1(stnode_t *node, test_op_t op, stnode_t *val1);
+
+void
+sttype_test_set2(stnode_t *node, test_op_t op, stnode_t *val1, stnode_t *val2);
+
+void
+sttype_test_set2_args(stnode_t *node, stnode_t *val1, stnode_t *val2);
+
+void
+sttype_test_get(stnode_t *node, test_op_t *p_op, stnode_t **p_val1, stnode_t **p_val2);
+
+#endif
diff --git a/epan/dfilter/syntax-tree.c b/epan/dfilter/syntax-tree.c
new file mode 100644
index 0000000000..238f685d84
--- /dev/null
+++ b/epan/dfilter/syntax-tree.c
@@ -0,0 +1,169 @@
+/* syntax-tree.c
+ *
+ * $Id: syntax-tree.c,v 1.1 2001/02/01 20:21:18 gram Exp $
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "syntax-tree.h"
+
+/* Keep track of sttype_t's via their sttype_id_t number */
+static sttype_t* type_list[STTYPE_NUM_TYPES];
+
+/* These are the sttype_t registration function prototypes. */
+void sttype_register_pointer(void);
+void sttype_register_range(void);
+void sttype_register_string(void);
+void sttype_register_test(void);
+
+
+#define STNODE_MAGIC 0xe9b00b9e
+
+
+void
+sttype_init(void)
+{
+ sttype_register_pointer();
+ sttype_register_range();
+ sttype_register_string();
+ sttype_register_test();
+}
+
+void
+sttype_cleanup(void)
+{
+ /* nothing to do */
+}
+
+
+void
+sttype_register(sttype_t *type)
+{
+ sttype_id_t type_id;
+
+ type_id = type->id;
+
+ /* Check input */
+ g_assert(type_id >= 0);
+ g_assert(type_id < STTYPE_NUM_TYPES);
+
+ /* Don't re-register. */
+ g_assert(type_list[type_id] == NULL);
+
+ type_list[type_id] = type;
+}
+
+static sttype_t*
+sttype_lookup(sttype_id_t type_id)
+{
+ sttype_t *result;
+
+ /* Check input */
+ g_assert(type_id >= 0);
+ g_assert(type_id < STTYPE_NUM_TYPES);
+
+ result = type_list[type_id];
+
+ /* Check output. */
+ g_assert(result != NULL);
+
+ return result;
+}
+
+
+stnode_t*
+stnode_new(sttype_id_t type_id, gpointer data)
+{
+ sttype_t *type;
+ stnode_t *node;
+
+ node = g_new(stnode_t, 1);
+ node->magic = STNODE_MAGIC;
+
+ if (type_id == STTYPE_UNINITIALIZED) {
+ node->type = NULL;
+ node->data = NULL;
+ }
+ else {
+ type = sttype_lookup(type_id);
+ g_assert(type);
+ node->type = type;
+ if (type->func_new) {
+ node->data = type->func_new(data);
+ }
+ else {
+ node->data = data;
+ }
+
+ }
+
+ return node;
+}
+
+void
+stnode_init(stnode_t *node, sttype_id_t type_id, gpointer data)
+{
+ sttype_t *type;
+
+ assert_magic(node, STNODE_MAGIC);
+ g_assert(!node->type);
+ g_assert(!node->data);
+
+ type = sttype_lookup(type_id);
+ g_assert(type);
+ node->type = type;
+ if (type->func_new) {
+ node->data = type->func_new(data);
+ }
+ else {
+ node->data = data;
+ }
+}
+
+void
+stnode_free(stnode_t *node)
+{
+ assert_magic(node, STNODE_MAGIC);
+ if (node->type) {
+ if (node->type->func_free) {
+ node->type->func_free(node->data);
+ }
+ }
+ else {
+ g_assert(!node->data);
+ }
+ g_free(node);
+}
+
+const char*
+stnode_type_name(stnode_t *node)
+{
+ assert_magic(node, STNODE_MAGIC);
+ if (node->type)
+ return node->type->name;
+ else
+ return "UNINITIALIZED";
+}
+
+sttype_id_t
+stnode_type_id(stnode_t *node)
+{
+ assert_magic(node, STNODE_MAGIC);
+ if (node->type)
+ return node->type->id;
+ else
+ return STTYPE_UNINITIALIZED;
+}
+
+gpointer
+stnode_data(stnode_t *node)
+{
+ assert_magic(node, STNODE_MAGIC);
+ if (node)
+ return node->data;
+ else
+ return NULL;
+}
diff --git a/epan/dfilter/syntax-tree.h b/epan/dfilter/syntax-tree.h
new file mode 100644
index 0000000000..3f60c09f1a
--- /dev/null
+++ b/epan/dfilter/syntax-tree.h
@@ -0,0 +1,95 @@
+/* syntax-tree.h
+ *
+ * $Id: syntax-tree.h,v 1.1 2001/02/01 20:21:18 gram Exp $
+ *
+ */
+#ifndef SYNTAX_TREE_H
+#define SYNTAX_TREE_H
+
+#include <glib.h>
+#include "cppmagic.h"
+
+typedef enum {
+ STTYPE_UNINITIALIZED,
+ STTYPE_TEST,
+ STTYPE_STRING,
+ STTYPE_FIELD,
+ STTYPE_FVALUE,
+ STTYPE_RANGE,
+ STTYPE_NUM_TYPES
+} sttype_id_t;
+
+typedef gpointer (*STTypeNewFunc)(gpointer);
+typedef void (*STTypeFreeFunc)(gpointer);
+
+
+/* Type information */
+typedef struct {
+ sttype_id_t id;
+ const char *name;
+ STTypeNewFunc func_new;
+ STTypeFreeFunc func_free;
+} sttype_t;
+
+/* Node (type instance) information */
+typedef struct {
+ guint32 magic;
+ sttype_t *type;
+ gpointer data;
+
+} stnode_t;
+
+void
+sttype_init(void);
+
+void
+sttype_cleanup(void);
+
+void
+sttype_register(sttype_t *type);
+
+stnode_t*
+stnode_new(sttype_id_t type_id, gpointer data);
+
+void
+stnode_init(stnode_t *node, sttype_id_t type_id, gpointer data);
+
+void
+stnode_free(stnode_t *node);
+
+const char*
+stnode_type_name(stnode_t *node);
+
+sttype_id_t
+stnode_type_id(stnode_t *node);
+
+gpointer
+stnode_data(stnode_t *node);
+
+#define assert_magic(obj, mnum) \
+ g_assert((obj)); \
+ if ((obj)->magic != (mnum)) { \
+ g_print("\nMagic num is 0x%08x, but should be 0x%08x", \
+ (obj)->magic, (mnum)); \
+ g_assert((obj)->magic == (mnum)); \
+ }
+
+
+
+
+#define STTYPE_ACCESSOR(ret,type,attr,magicnum) \
+ ret \
+ CONCAT(CONCAT(CONCAT(sttype_,type),_),attr) (stnode_t *node) \
+{\
+ CONCAT(type,_t) *value; \
+ value = stnode_data(node);\
+ assert_magic(value, magicnum); \
+ return value->attr; \
+}
+
+#define STTYPE_ACCESSOR_PROTOTYPE(ret,type,attr) \
+ ret \
+ CONCAT(CONCAT(CONCAT(sttype_,type),_),attr) (stnode_t *node);
+
+
+#endif
diff --git a/epan/epan.c b/epan/epan.c
index 74f89d9b15..7ebf350f12 100644
--- a/epan/epan.c
+++ b/epan/epan.c
@@ -1,6 +1,6 @@
/* epan.h
*
- * $Id: epan.c,v 1.5 2001/01/26 06:14:50 guy Exp $
+ * $Id: epan.c,v 1.6 2001/02/01 20:21:16 gram Exp $
*
* Ethereal Protocol Analyzer Library
*
@@ -14,7 +14,7 @@
#include <epan.h>
#include "conversation.h"
-#include "dfilter.h"
+#include "dfilter/dfilter.h"
#include "except.h"
#include "packet.h"
#include "proto.h"
@@ -69,11 +69,6 @@ epan_conversation_init(void)
}
-struct epan_dissect {
-
- tvbuff_t *tvb;
- proto_tree *tree;
-};
epan_dissect_t*
epan_dissect_new(void* pseudo_header, const guint8* data, frame_data *fd, proto_tree *tree)
@@ -83,6 +78,8 @@ epan_dissect_new(void* pseudo_header, const guint8* data, frame_data *fd, proto_
edt = g_new(epan_dissect_t, 1);
/* XXX - init tree */
+ edt->tree = tree;
+
dissect_packet(&edt->tvb, pseudo_header, data, fd, tree);
return edt;
diff --git a/epan/epan.h b/epan/epan.h
index 3c6a921206..9f94865f2e 100644
--- a/epan/epan.h
+++ b/epan/epan.h
@@ -1,6 +1,6 @@
/* epan.h
*
- * $Id: epan.h,v 1.4 2000/10/16 23:17:39 guy Exp $
+ * $Id: epan.h,v 1.5 2001/02/01 20:21:16 gram Exp $
*
* Ethereal Protocol Analyzer Library
*
@@ -44,7 +44,10 @@ epan_free(epan_t*);
* as the structures that the epan_dissect_t contains might have pointers
* to addresses in your byte array.
*/
-typedef struct epan_dissect epan_dissect_t;
+typedef struct {
+ tvbuff_t *tvb;
+ proto_tree *tree;
+} epan_dissect_t;
epan_dissect_t*
epan_dissect_new(void* pseudo_header, const guint8* data, frame_data *fd, proto_tree *tree);
diff --git a/epan/exceptions.h b/epan/exceptions.h
index 19eda9fe2b..54932dd2f5 100644
--- a/epan/exceptions.h
+++ b/epan/exceptions.h
@@ -11,6 +11,7 @@
/* Ethereal's exceptions */
#define BoundsError 1 /* Index is out of range */
#define ReportedBoundsError 2 /* Index is beyond reported length (not cap_len) */
+#define TypeError 3 /* During dfilter parsing */
/* Usage:
*
diff --git a/epan/ftypes/.cvsignore b/epan/ftypes/.cvsignore
new file mode 100644
index 0000000000..601c4fbff4
--- /dev/null
+++ b/epan/ftypes/.cvsignore
@@ -0,0 +1,4 @@
+.cvsignore
+.deps
+Makefile
+Makefile.in
diff --git a/epan/ftypes/Makefile.am b/epan/ftypes/Makefile.am
new file mode 100644
index 0000000000..3af23be17c
--- /dev/null
+++ b/epan/ftypes/Makefile.am
@@ -0,0 +1,52 @@
+# Makefile.am
+# Automake file for the GTK interface routines for Ethereal
+#
+# $Id: Makefile.am,v 1.1 2001/02/01 20:21:19 gram Exp $
+#
+# Ethereal - Network traffic analyzer
+# By Gerald Combs <gerald@zing.org>
+# Copyright 1998 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.
+
+# We produce an archive library. In the future, when libethereal is a
+# shared library, this will be linked into libethereal. While libethereal
+# is an archive library, any executable linking against libethereal will
+# also need to link against libftypes.
+noinst_LIBRARIES = libftypes.a
+
+CLEANFILES = \
+ libftypes.a \
+ *~
+
+INCLUDES = -I$(srcdir)/../..
+
+libftypes_a_SOURCES = \
+ ftypes.c \
+ ftypes.h \
+ ftypes-int.h \
+ ftype-bytes.c \
+ ftype-double.c \
+ ftype-integer.c \
+ ftype-ipv4.c \
+ ftype-none.c \
+ ftype-string.c \
+ ftype-time.c \
+ ftype-tvbuff.c
+
+#EXTRA_DIST = \
+# Makefile.nmake
+
diff --git a/epan/ftypes/ftype-bytes.c b/epan/ftypes/ftype-bytes.c
new file mode 100644
index 0000000000..726bbbd707
--- /dev/null
+++ b/epan/ftypes/ftype-bytes.c
@@ -0,0 +1,386 @@
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <ftypes-int.h>
+#include <string.h>
+#include <ctype.h>
+#include "resolv.h"
+
+#define ETHER_LEN 6
+#define IPv6_LEN 16
+
+static void
+ftype_from_tvbuff(field_info *fi, tvbuff_t *tvb, int start, int length,
+ gboolean little_endian)
+{
+ /* XXX */
+ g_assert_not_reached();
+}
+
+
+static void
+bytes_fvalue_new(fvalue_t *fv)
+{
+ fv->value.bytes = NULL;
+}
+
+void
+bytes_fvalue_free(fvalue_t *fv)
+{
+ if (fv->value.bytes) {
+ g_byte_array_free(fv->value.bytes, TRUE);
+ }
+}
+
+
+static void
+bytes_fvalue_set(fvalue_t *fv, gpointer value, gboolean already_copied)
+{
+ g_assert(already_copied);
+ fv->value.bytes = value;
+}
+
+static void
+common_fvalue_set(fvalue_t *fv, guint8* data, guint len)
+{
+ fv->value.bytes = g_byte_array_new();
+ g_byte_array_append(fv->value.bytes, data, len);
+}
+
+static void
+ether_fvalue_set(fvalue_t *fv, gpointer value, gboolean already_copied)
+{
+ g_assert(!already_copied);
+ common_fvalue_set(fv, value, ETHER_LEN);
+}
+
+static void
+ipv6_fvalue_set(fvalue_t *fv, gpointer value, gboolean already_copied)
+{
+ g_assert(!already_copied);
+ common_fvalue_set(fv, value, IPv6_LEN);
+}
+
+static gpointer
+value_get(fvalue_t *fv)
+{
+ return fv->value.bytes->data;
+}
+
+static gboolean
+is_byte_sep(guint8 c)
+{
+ return (c == '-' || c == ':' || c == '.');
+}
+
+static gboolean
+val_from_string(fvalue_t *fv, char *s, LogFunc log)
+{
+ GByteArray *bytes;
+ guint8 val;
+ char *p, *q, *punct;
+ char two_digits[3];
+ char one_digit[2];
+ gboolean fail = FALSE;
+
+ bytes = g_byte_array_new();
+
+ p = s;
+ while (*p) {
+ q = p+1;
+ if (*q && isxdigit(*p) && isxdigit(*q)) {
+ two_digits[0] = *p;
+ two_digits[1] = *q;
+ two_digits[2] = '\0';
+
+ val = (guint8) strtoul(two_digits, NULL, 16);
+ g_byte_array_append(bytes, &val, 1);
+ punct = q + 1;
+ if (*punct) {
+ if (is_byte_sep(*punct)) {
+ p = punct + 1;
+ continue;
+ }
+ else {
+ fail = TRUE;
+ break;
+ }
+ }
+ else {
+ p = punct;
+ continue;
+ }
+ }
+ else if (*q && isxdigit(*p) && is_byte_sep(*q)) {
+ one_digit[0] = *p;
+ one_digit[1] = '\0';
+
+ val = (guint8) strtoul(one_digit, NULL, 16);
+ g_byte_array_append(bytes, &val, 1);
+ p = q + 1;
+ continue;
+ }
+ else if (!*q && isxdigit(*p)) {
+ one_digit[0] = *p;
+ one_digit[1] = '\0';
+
+ val = (guint8) strtoul(one_digit, NULL, 16);
+ g_byte_array_append(bytes, &val, 1);
+ p = q;
+ continue;
+ }
+ else {
+ fail = TRUE;
+ break;
+ }
+ }
+
+ if (fail) {
+ g_byte_array_free(bytes, TRUE);
+ return FALSE;
+ }
+
+ fv->value.bytes = bytes;
+
+
+ return TRUE;
+}
+
+static gboolean
+ether_from_string(fvalue_t *fv, char *s, LogFunc log)
+{
+ guint8 *mac;
+
+ if (val_from_string(fv, s, log)) {
+ return TRUE;
+ }
+
+ mac = get_ether_addr(s);
+ if (!mac) {
+ return FALSE;
+ }
+
+ ether_fvalue_set(fv, mac, FALSE);
+ return TRUE;
+}
+
+static gboolean
+ipv6_from_string(fvalue_t *fv, char *s, LogFunc log)
+{
+ guint8 buffer[16];
+
+ if (!get_host_ipaddr6(s, (struct e_in6_addr*)buffer)) {
+ return FALSE;
+ }
+
+ ipv6_fvalue_set(fv, buffer, FALSE);
+ return TRUE;
+}
+
+static guint
+len(fvalue_t *fv)
+{
+ return fv->value.bytes->len;
+}
+
+static void
+slice(fvalue_t *fv, GByteArray *bytes, guint offset, guint length)
+{
+ guint8* data;
+
+ data = fv->value.bytes->data + offset;
+
+ g_byte_array_append(bytes, data, length);
+}
+
+
+static gboolean
+cmp_eq(fvalue_t *fv_a, fvalue_t *fv_b)
+{
+ GByteArray *a = fv_a->value.bytes;
+ GByteArray *b = fv_b->value.bytes;
+
+ if (a->len != b->len) {
+ return FALSE;
+ }
+
+ return (memcmp(a->data, b->data, a->len) == 0);
+}
+
+
+static gboolean
+cmp_ne(fvalue_t *fv_a, fvalue_t *fv_b)
+{
+ GByteArray *a = fv_a->value.bytes;
+ GByteArray *b = fv_b->value.bytes;
+
+ if (a->len != b->len) {
+ return FALSE;
+ }
+
+ return (memcmp(a->data, b->data, a->len) != 0);
+}
+
+
+static gboolean
+cmp_gt(fvalue_t *fv_a, fvalue_t *fv_b)
+{
+ GByteArray *a = fv_a->value.bytes;
+ GByteArray *b = fv_b->value.bytes;
+
+ if (a->len > b->len) {
+ return TRUE;
+ }
+
+ if (a->len < b->len) {
+ return FALSE;
+ }
+
+ return (memcmp(a->data, b->data, a->len) > 0);
+}
+
+static gboolean
+cmp_ge(fvalue_t *fv_a, fvalue_t *fv_b)
+{
+ GByteArray *a = fv_a->value.bytes;
+ GByteArray *b = fv_b->value.bytes;
+
+ if (a->len > b->len) {
+ return TRUE;
+ }
+
+ if (a->len < b->len) {
+ return FALSE;
+ }
+
+ return (memcmp(a->data, b->data, a->len) >= 0);
+}
+
+static gboolean
+cmp_lt(fvalue_t *fv_a, fvalue_t *fv_b)
+{
+ GByteArray *a = fv_a->value.bytes;
+ GByteArray *b = fv_b->value.bytes;
+
+ if (a->len < b->len) {
+ return TRUE;
+ }
+
+ if (a->len > b->len) {
+ return FALSE;
+ }
+
+ return (memcmp(a->data, b->data, a->len) < 0);
+}
+
+static gboolean
+cmp_le(fvalue_t *fv_a, fvalue_t *fv_b)
+{
+ GByteArray *a = fv_a->value.bytes;
+ GByteArray *b = fv_b->value.bytes;
+
+ if (a->len < b->len) {
+ return TRUE;
+ }
+
+ if (a->len > b->len) {
+ return FALSE;
+ }
+
+ return (memcmp(a->data, b->data, a->len) <= 0);
+}
+
+void
+ftype_register_bytes(void)
+{
+
+ static ftype_t bytes_type = {
+ "FT_BYTES",
+ "sequence of bytes",
+ 0,
+ bytes_fvalue_new,
+ bytes_fvalue_free,
+ ftype_from_tvbuff,
+ val_from_string,
+
+ bytes_fvalue_set,
+ NULL,
+ NULL,
+
+ value_get,
+ NULL,
+ NULL,
+
+ cmp_eq,
+ cmp_ne,
+ cmp_gt,
+ cmp_ge,
+ cmp_lt,
+ cmp_le,
+
+ len,
+ slice,
+ };
+
+ static ftype_t ether_type = {
+ "FT_ETHER",
+ "Ethernet or other MAC address",
+ ETHER_LEN,
+ bytes_fvalue_new,
+ bytes_fvalue_free,
+ ftype_from_tvbuff,
+ ether_from_string,
+
+ ether_fvalue_set,
+ NULL,
+ NULL,
+
+ value_get,
+ NULL,
+ NULL,
+
+ cmp_eq,
+ cmp_ne,
+ cmp_gt,
+ cmp_ge,
+ cmp_lt,
+ cmp_le,
+
+ len,
+ slice,
+ };
+
+ static ftype_t ipv6_type = {
+ "FT_IPv6",
+ "IPv6 address",
+ IPv6_LEN,
+ bytes_fvalue_new,
+ bytes_fvalue_free,
+ ftype_from_tvbuff,
+ ipv6_from_string,
+
+ ipv6_fvalue_set,
+ NULL,
+ NULL,
+
+ value_get,
+ NULL,
+ NULL,
+
+ cmp_eq,
+ cmp_ne,
+ cmp_gt,
+ cmp_ge,
+ cmp_lt,
+ cmp_le,
+
+ len,
+ slice,
+ };
+
+ ftype_register(FT_BYTES, &bytes_type);
+ ftype_register(FT_ETHER, &ether_type);
+ ftype_register(FT_IPv6, &ipv6_type);
+}
diff --git a/epan/ftypes/ftype-double.c b/epan/ftypes/ftype-double.c
new file mode 100644
index 0000000000..146794a597
--- /dev/null
+++ b/epan/ftypes/ftype-double.c
@@ -0,0 +1,133 @@
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <ftypes-int.h>
+#include <stdlib.h>
+#include <math.h>
+#include <errno.h>
+
+static void
+ftype_from_tvbuff(field_info *fi, tvbuff_t *tvb, int start, int length,
+ gboolean little_endian)
+{
+ /* XXX */
+ g_assert_not_reached();
+}
+
+
+static void
+double_fvalue_new(fvalue_t *fv)
+{
+ fv->value.floating = 0.0;
+}
+
+static void
+double_fvalue_set_floating(fvalue_t *fv, gdouble value)
+{
+ fv->value.floating = value;
+}
+
+static double
+value_get_floating(fvalue_t *fv)
+{
+ return fv->value.floating;
+}
+
+static gboolean
+val_from_string(fvalue_t *fv, char *s, LogFunc log)
+{
+ char *endptr = NULL;
+
+ fv->value.floating = strtod(s, &endptr);
+
+ if (endptr == s || *endptr != '\0') {
+ /* This isn't a valid number. */
+ log("\"%s\" is not a valid number.", s);
+ return FALSE;
+ }
+ if (errno == ERANGE) {
+ if (fv->value.floating == 0) {
+ log("\"%s\" causes floating-point underflow.", s);
+ }
+ else if (fv->value.floating == HUGE_VAL) {
+ log("\"%s\" causes floating-point overflow.", s);
+ }
+ else {
+ log("\"%s\" is not a valid floating-point number.", s);
+ }
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+static gboolean
+cmp_eq(fvalue_t *a, fvalue_t *b)
+{
+ return a->value.floating == b->value.floating;
+}
+
+static gboolean
+cmp_ne(fvalue_t *a, fvalue_t *b)
+{
+ return a->value.floating != b->value.floating;
+}
+
+static gboolean
+cmp_gt(fvalue_t *a, fvalue_t *b)
+{
+ return a->value.floating > b->value.floating;
+}
+
+static gboolean
+cmp_ge(fvalue_t *a, fvalue_t *b)
+{
+ return a->value.floating >= b->value.floating;
+}
+
+static gboolean
+cmp_lt(fvalue_t *a, fvalue_t *b)
+{
+ return a->value.floating < b->value.floating;
+}
+
+static gboolean
+cmp_le(fvalue_t *a, fvalue_t *b)
+{
+ return a->value.floating <= b->value.floating;
+}
+
+void
+ftype_register_double(void)
+{
+
+ static ftype_t double_type = {
+ "FT_DOUBLE",
+ "floating point",
+ 0,
+ double_fvalue_new,
+ NULL,
+ ftype_from_tvbuff,
+ val_from_string,
+
+ NULL,
+ NULL,
+ double_fvalue_set_floating,
+
+ NULL,
+ NULL,
+ value_get_floating,
+
+ cmp_eq,
+ cmp_ne,
+ cmp_gt,
+ cmp_ge,
+ cmp_lt,
+ cmp_le,
+ };
+
+ ftype_register(FT_DOUBLE, &double_type);
+}
diff --git a/epan/ftypes/ftype-integer.c b/epan/ftypes/ftype-integer.c
new file mode 100644
index 0000000000..cef237c7ed
--- /dev/null
+++ b/epan/ftypes/ftype-integer.c
@@ -0,0 +1,417 @@
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+
+#ifdef NEED_SNPRINTF_H
+#include "snprintf.h"
+#endif
+
+#include <stdlib.h>
+#include <errno.h>
+#include "ftypes-int.h"
+#include "resolv.h"
+
+
+static void
+ftype_from_tvbuff(field_info *fi, tvbuff_t *tvb, int start, int length,
+ gboolean little_endian)
+{
+ /* XXX */
+ g_assert_not_reached();
+}
+
+
+static void
+int_fvalue_new(fvalue_t *fv)
+{
+ fv->value.integer = 0;
+}
+
+static void
+set_integer(fvalue_t *fv, guint32 value)
+{
+ fv->value.integer = value;
+}
+
+static guint32
+get_integer(fvalue_t *fv)
+{
+ return fv->value.integer;
+}
+
+static gboolean
+val_from_string(fvalue_t *fv, char *s, LogFunc log)
+{
+ char *endptr;
+
+ fv->value.integer = strtoul(s, &endptr, 0);
+
+ if (endptr == s || *endptr != '\0') {
+ /* This isn't a valid number. */
+ log("\"%s\" is not a valid number.", s);
+ return FALSE;
+ }
+ if (errno == ERANGE) {
+ if (fv->value.integer == ULONG_MAX) {
+ log("\"%s\" causes an integer overflow.", s);
+ }
+ else {
+ log("\"%s\" is not an integer.", s);
+ }
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static gboolean
+ipxnet_from_string(fvalue_t *fv, char *s, LogFunc log)
+{
+ guint32 val;
+ gboolean known;
+
+ if (val_from_string(fv, s, log)) {
+ return TRUE;
+ }
+
+ val = get_ipxnet_addr(s, &known);
+ if (known) {
+ fv->value.integer = val;
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static gboolean
+cmp_eq(fvalue_t *a, fvalue_t *b)
+{
+ return a->value.integer == b->value.integer;
+}
+
+static gboolean
+cmp_ne(fvalue_t *a, fvalue_t *b)
+{
+ return a->value.integer != b->value.integer;
+}
+
+static gboolean
+u_cmp_gt(fvalue_t *a, fvalue_t *b)
+{
+ return (int)a->value.integer > (int)b->value.integer;
+}
+
+static gboolean
+u_cmp_ge(fvalue_t *a, fvalue_t *b)
+{
+ return (int)a->value.integer >= (int)b->value.integer;
+}
+
+static gboolean
+u_cmp_lt(fvalue_t *a, fvalue_t *b)
+{
+ return (int)a->value.integer < (int)b->value.integer;
+}
+
+static gboolean
+u_cmp_le(fvalue_t *a, fvalue_t *b)
+{
+ return (int)a->value.integer <= (int)b->value.integer;
+}
+
+static gboolean
+s_cmp_gt(fvalue_t *a, fvalue_t *b)
+{
+ return a->value.integer > b->value.integer;
+}
+
+static gboolean
+s_cmp_ge(fvalue_t *a, fvalue_t *b)
+{
+ return a->value.integer >= b->value.integer;
+}
+
+static gboolean
+s_cmp_lt(fvalue_t *a, fvalue_t *b)
+{
+ return a->value.integer < b->value.integer;
+}
+
+static gboolean
+s_cmp_le(fvalue_t *a, fvalue_t *b)
+{
+ return a->value.integer <= b->value.integer;
+}
+
+/* BOOLEAN-specific */
+
+static void
+boolean_fvalue_new(fvalue_t *fv)
+{
+ fv->value.integer = TRUE;
+}
+
+
+
+
+
+void
+ftype_register_integers(void)
+{
+
+ static ftype_t uint8_type = {
+ "FT_UINT8",
+ "unsigned, 1 byte",
+ 1,
+ int_fvalue_new,
+ NULL,
+ ftype_from_tvbuff,
+ val_from_string,
+
+ NULL,
+ set_integer,
+ NULL,
+
+ NULL,
+ get_integer,
+ NULL,
+
+ cmp_eq,
+ cmp_ne,
+ u_cmp_gt,
+ u_cmp_ge,
+ u_cmp_lt,
+ u_cmp_le,
+ };
+ static ftype_t uint16_type = {
+ "FT_UINT16",
+ "unsigned, 2 bytes",
+ 2,
+ int_fvalue_new,
+ NULL,
+ ftype_from_tvbuff,
+ val_from_string,
+
+ NULL,
+ set_integer,
+ NULL,
+
+ NULL,
+ get_integer,
+ NULL,
+
+ cmp_eq,
+ cmp_ne,
+ u_cmp_gt,
+ u_cmp_ge,
+ u_cmp_lt,
+ u_cmp_le,
+ };
+ static ftype_t uint24_type = {
+ "FT_UINT24",
+ "unsigned, 3 bytes",
+ 3,
+ int_fvalue_new,
+ NULL,
+ ftype_from_tvbuff,
+ val_from_string,
+
+ NULL,
+ set_integer,
+ NULL,
+
+ NULL,
+ get_integer,
+ NULL,
+
+ cmp_eq,
+ cmp_ne,
+ u_cmp_gt,
+ u_cmp_ge,
+ u_cmp_lt,
+ u_cmp_le,
+ };
+ static ftype_t uint32_type = {
+ "FT_UINT32",
+ "unsigned, 4 bytes",
+ 4,
+ int_fvalue_new,
+ NULL,
+ ftype_from_tvbuff,
+ val_from_string,
+
+ NULL,
+ set_integer,
+ NULL,
+
+ NULL,
+ get_integer,
+ NULL,
+
+ cmp_eq,
+ cmp_ne,
+ u_cmp_gt,
+ u_cmp_ge,
+ u_cmp_lt,
+ u_cmp_le,
+ };
+ static ftype_t int8_type = {
+ "FT_INT8",
+ "signed, 1 byte",
+ 1,
+ int_fvalue_new,
+ NULL,
+ ftype_from_tvbuff,
+ val_from_string,
+
+ NULL,
+ set_integer,
+ NULL,
+
+ NULL,
+ get_integer,
+ NULL,
+
+ cmp_eq,
+ cmp_ne,
+ s_cmp_gt,
+ s_cmp_ge,
+ s_cmp_lt,
+ s_cmp_le,
+ };
+ static ftype_t int16_type = {
+ "FT_INT16",
+ "signed, 2 bytes",
+ 2,
+ int_fvalue_new,
+ NULL,
+ ftype_from_tvbuff,
+ val_from_string,
+
+ NULL,
+ set_integer,
+ NULL,
+
+ NULL,
+ get_integer,
+ NULL,
+
+ cmp_eq,
+ cmp_ne,
+ s_cmp_gt,
+ s_cmp_ge,
+ s_cmp_lt,
+ s_cmp_le,
+ };
+ static ftype_t int24_type = {
+ "FT_INT24",
+ "signed, 3 bytes",
+ 3,
+ int_fvalue_new,
+ NULL,
+ ftype_from_tvbuff,
+ val_from_string,
+
+ NULL,
+ set_integer,
+ NULL,
+
+ NULL,
+ get_integer,
+ NULL,
+
+ cmp_eq,
+ cmp_ne,
+ s_cmp_gt,
+ s_cmp_ge,
+ s_cmp_lt,
+ s_cmp_le,
+ };
+ static ftype_t int32_type = {
+ "FT_INT32",
+ "signed, 4 bytes",
+ 4,
+ int_fvalue_new,
+ NULL,
+ ftype_from_tvbuff,
+ val_from_string,
+
+ NULL,
+ set_integer,
+ NULL,
+
+ NULL,
+ get_integer,
+ NULL,
+
+ cmp_eq,
+ cmp_ne,
+ s_cmp_gt,
+ s_cmp_ge,
+ s_cmp_lt,
+ s_cmp_le,
+ };
+ static ftype_t boolean_type = {
+ "FT_BOOLEAN",
+ "Boolean",
+ 0,
+ boolean_fvalue_new,
+ NULL,
+ ftype_from_tvbuff,
+ val_from_string,
+
+ NULL,
+ set_integer,
+ NULL,
+
+ NULL,
+ get_integer,
+ NULL,
+
+ cmp_eq,
+ cmp_ne,
+ u_cmp_gt,
+ u_cmp_ge,
+ u_cmp_lt,
+ u_cmp_le,
+ };
+
+ static ftype_t ipxnet_type = {
+ "FT_IPXNET",
+ "IPX network number",
+ 4,
+ int_fvalue_new,
+ NULL,
+ ftype_from_tvbuff,
+ ipxnet_from_string,
+
+ NULL,
+ set_integer,
+ NULL,
+
+ NULL,
+ get_integer,
+ NULL,
+
+ cmp_eq,
+ cmp_ne,
+ u_cmp_gt,
+ u_cmp_ge,
+ u_cmp_lt,
+ u_cmp_le,
+ };
+
+
+ ftype_register(FT_UINT8, &uint8_type);
+ ftype_register(FT_UINT16, &uint16_type);
+ ftype_register(FT_UINT24, &uint24_type);
+ ftype_register(FT_UINT32, &uint32_type);
+ ftype_register(FT_INT8, &int8_type);
+ ftype_register(FT_INT16, &int16_type);
+ ftype_register(FT_INT24, &int24_type);
+ ftype_register(FT_INT32, &int32_type);
+ ftype_register(FT_BOOLEAN, &boolean_type);
+ ftype_register(FT_IPXNET, &ipxnet_type);
+}
diff --git a/epan/ftypes/ftype-ipv4.c b/epan/ftypes/ftype-ipv4.c
new file mode 100644
index 0000000000..eae5677a25
--- /dev/null
+++ b/epan/ftypes/ftype-ipv4.c
@@ -0,0 +1,114 @@
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <ftypes-int.h>
+#include "ipv4.h"
+#include "resolv.h"
+
+static void
+ftype_from_tvbuff(field_info *fi, tvbuff_t *tvb, int start, int length,
+ gboolean little_endian)
+{
+ /* XXX */
+ g_assert_not_reached();
+}
+
+
+
+static void
+set_integer(fvalue_t *fv, guint32 value)
+{
+ ipv4_addr_set_net_order_addr(&(fv->value.ipv4), value);
+ ipv4_addr_set_netmask_bits(&(fv->value.ipv4), 32);
+}
+
+static gpointer
+value_get(fvalue_t *fv)
+{
+ return &(fv->value.ipv4);
+}
+
+static gboolean
+val_from_string(fvalue_t *fv, char *s, LogFunc log)
+{
+ guint32 addr;
+
+ if (!get_host_ipaddr(s, &addr)) {
+ log("\"%s\" is not a valid hostname or IPv4 address.", s);
+ return FALSE;
+ }
+ ipv4_addr_set_host_order_addr(&(fv->value.ipv4), addr);
+ /*ipv4_addr_set_netmask_bits(&node->value.ipv4, nmask_bits);*/
+ ipv4_addr_set_netmask_bits(&(fv->value.ipv4), 32);
+ return TRUE;
+}
+
+static gboolean
+cmp_eq(fvalue_t *a, fvalue_t *b)
+{
+ return ipv4_addr_eq(&a->value.ipv4, &b->value.ipv4);
+}
+
+static gboolean
+cmp_ne(fvalue_t *a, fvalue_t *b)
+{
+ return ipv4_addr_ne(&a->value.ipv4, &b->value.ipv4);
+}
+
+static gboolean
+cmp_gt(fvalue_t *a, fvalue_t *b)
+{
+ return ipv4_addr_gt(&a->value.ipv4, &b->value.ipv4);
+}
+
+static gboolean
+cmp_ge(fvalue_t *a, fvalue_t *b)
+{
+ return ipv4_addr_ge(&a->value.ipv4, &b->value.ipv4);
+}
+
+static gboolean
+cmp_lt(fvalue_t *a, fvalue_t *b)
+{
+ return ipv4_addr_lt(&a->value.ipv4, &b->value.ipv4);
+}
+
+static gboolean
+cmp_le(fvalue_t *a, fvalue_t *b)
+{
+ return ipv4_addr_le(&a->value.ipv4, &b->value.ipv4);
+}
+
+void
+ftype_register_ipv4(void)
+{
+
+ static ftype_t ipv4_type = {
+ "FT_IPv4",
+ "IPv4 address",
+ 4,
+ NULL,
+ NULL,
+ ftype_from_tvbuff,
+ val_from_string,
+
+ NULL,
+ set_integer,
+ NULL,
+
+ value_get,
+ NULL,
+ NULL,
+
+ cmp_eq,
+ cmp_ne,
+ cmp_gt,
+ cmp_ge,
+ cmp_lt,
+ cmp_le,
+ };
+
+ ftype_register(FT_IPv4, &ipv4_type);
+}
diff --git a/epan/ftypes/ftype-none.c b/epan/ftypes/ftype-none.c
new file mode 100644
index 0000000000..1bb64a3759
--- /dev/null
+++ b/epan/ftypes/ftype-none.c
@@ -0,0 +1,20 @@
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <ftypes-int.h>
+
+
+void
+ftype_register_none(void)
+{
+
+ static ftype_t none_type = {
+ "FT_NONE",
+ "label",
+ 0,
+ };
+
+ ftype_register(FT_NONE, &none_type);
+}
diff --git a/epan/ftypes/ftype-string.c b/epan/ftypes/ftype-string.c
new file mode 100644
index 0000000000..38ce87faa0
--- /dev/null
+++ b/epan/ftypes/ftype-string.c
@@ -0,0 +1,198 @@
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <ftypes-int.h>
+#include <string.h>
+
+static void
+ftype_from_tvbuff(field_info *fi, tvbuff_t *tvb, int start, int length,
+ gboolean little_endian)
+{
+ /* XXX */
+ g_assert_not_reached();
+}
+
+
+static void
+string_fvalue_new(fvalue_t *fv)
+{
+ fv->value.string = NULL;
+}
+
+static void
+string_fvalue_free(fvalue_t *fv)
+{
+ if (fv->value.string) {
+ g_free(fv->value.string);
+ }
+}
+
+static void
+string_fvalue_set(fvalue_t *fv, gpointer value, gboolean already_copied)
+{
+ if (already_copied) {
+ fv->value.string = value;
+ }
+ else {
+ fv->value.string = g_strdup(value);
+ }
+}
+
+static gpointer
+value_get(fvalue_t *fv)
+{
+ return fv->value.string;
+}
+
+static gboolean
+val_from_string(fvalue_t *fv, char *s, LogFunc log)
+{
+ fv->value.string = g_strdup(s);
+ return TRUE;
+}
+
+static guint
+len(fvalue_t *fv)
+{
+ return strlen(fv->value.string);
+}
+
+static void
+slice(fvalue_t *fv, GByteArray *bytes, guint offset, guint length)
+{
+ guint8* data;
+
+ data = fv->value.string + offset;
+
+ g_byte_array_append(bytes, data, length);
+}
+
+
+static gboolean
+cmp_eq(fvalue_t *a, fvalue_t *b)
+{
+ return (strcmp(a->value.string, b->value.string) == 0);
+}
+
+static gboolean
+cmp_ne(fvalue_t *a, fvalue_t *b)
+{
+ return (strcmp(a->value.string, b->value.string) != 0);
+}
+
+static gboolean
+cmp_gt(fvalue_t *a, fvalue_t *b)
+{
+ return (strcmp(a->value.string, b->value.string) > 0);
+}
+
+static gboolean
+cmp_ge(fvalue_t *a, fvalue_t *b)
+{
+ return (strcmp(a->value.string, b->value.string) >= 0);
+}
+
+static gboolean
+cmp_lt(fvalue_t *a, fvalue_t *b)
+{
+ return (strcmp(a->value.string, b->value.string) < 0);
+}
+
+static gboolean
+cmp_le(fvalue_t *a, fvalue_t *b)
+{
+ return (strcmp(a->value.string, b->value.string) <= 0);
+}
+
+void
+ftype_register_string(void)
+{
+
+ static ftype_t string_type = {
+ "FT_STRING",
+ "character string",
+ 0,
+ string_fvalue_new,
+ string_fvalue_free,
+ ftype_from_tvbuff,
+ val_from_string,
+
+ string_fvalue_set,
+ NULL,
+ NULL,
+
+ value_get,
+ NULL,
+ NULL,
+
+ cmp_eq,
+ cmp_ne,
+ cmp_gt,
+ cmp_ge,
+ cmp_lt,
+ cmp_le,
+
+ len,
+ slice,
+ };
+ static ftype_t stringz_type = {
+ "FT_STRINGZ",
+ "character string",
+ 0,
+ string_fvalue_new,
+ string_fvalue_free,
+ ftype_from_tvbuff,
+ val_from_string,
+
+ string_fvalue_set,
+ NULL,
+ NULL,
+
+ value_get,
+ NULL,
+ NULL,
+
+ cmp_eq,
+ cmp_ne,
+ cmp_gt,
+ cmp_ge,
+ cmp_lt,
+ cmp_le,
+
+ len,
+ slice,
+ };
+ static ftype_t uint_string_type = {
+ "FT_UINT_STRING",
+ "character string",
+ 0,
+ string_fvalue_new,
+ string_fvalue_free,
+ ftype_from_tvbuff,
+ val_from_string,
+
+ string_fvalue_set,
+ NULL,
+ NULL,
+
+ value_get,
+ NULL,
+ NULL,
+
+ cmp_eq,
+ cmp_ne,
+ cmp_gt,
+ cmp_ge,
+ cmp_lt,
+ cmp_le,
+
+ len,
+ slice,
+ };
+
+ ftype_register(FT_STRING, &string_type);
+ ftype_register(FT_STRINGZ, &stringz_type);
+ ftype_register(FT_UINT_STRING, &uint_string_type);
+}
diff --git a/epan/ftypes/ftype-time.c b/epan/ftypes/ftype-time.c
new file mode 100644
index 0000000000..6eb2a3d4cb
--- /dev/null
+++ b/epan/ftypes/ftype-time.c
@@ -0,0 +1,78 @@
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <ftypes-int.h>
+
+static void
+ftype_from_tvbuff(field_info *fi, tvbuff_t *tvb, int start, int length,
+ gboolean little_endian)
+{
+ /* XXX */
+ g_assert_not_reached();
+}
+
+
+static void
+time_fvalue_new(fvalue_t *fv)
+{
+ fv->value.time.tv_sec = 0;
+ fv->value.time.tv_usec = 0;
+}
+
+static void
+time_fvalue_set(fvalue_t *fv, gpointer value, gboolean already_copied)
+{
+ g_assert(!already_copied);
+ memcpy(&(fv->value.time), value, sizeof(struct timeval));
+}
+
+static gpointer
+value_get(fvalue_t *fv)
+{
+ return &(fv->value.time);
+}
+
+void
+ftype_register_time(void)
+{
+
+ static ftype_t abstime_type = {
+ "FT_ABSOLUTE_TIME",
+ "date/time",
+ 0,
+ time_fvalue_new,
+ NULL,
+ ftype_from_tvbuff,
+ NULL,
+
+ time_fvalue_set,
+ NULL,
+ NULL,
+
+ value_get,
+ NULL,
+ NULL
+ };
+ static ftype_t reltime_type = {
+ "FT_RELATIVE_TIME",
+ "time offset",
+ 0,
+ time_fvalue_new,
+ NULL,
+ ftype_from_tvbuff,
+ NULL,
+
+ time_fvalue_set,
+ NULL,
+ NULL,
+
+ value_get,
+ NULL,
+ NULL
+ };
+
+ ftype_register(FT_ABSOLUTE_TIME, &abstime_type);
+ ftype_register(FT_RELATIVE_TIME, &reltime_type);
+}
diff --git a/epan/ftypes/ftype-tvbuff.c b/epan/ftypes/ftype-tvbuff.c
new file mode 100644
index 0000000000..e9617ca607
--- /dev/null
+++ b/epan/ftypes/ftype-tvbuff.c
@@ -0,0 +1,84 @@
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <ftypes-int.h>
+#include "gdebug.h"
+
+static void
+value_new(fvalue_t *fv)
+{
+ fv->value.tvb = NULL;
+}
+
+
+static void
+value_set(fvalue_t *fv, gpointer value, gboolean already_copied)
+{
+ g_assert(already_copied);
+ fv->value.tvb = value;
+}
+
+static gpointer
+value_get(fvalue_t *fv)
+{
+ return fv->value.tvb;
+}
+
+static guint
+len(fvalue_t *fv)
+{
+ if (fv->value.tvb)
+ return tvb_length(fv->value.tvb);
+ else
+ return 0;
+}
+
+static void
+slice(fvalue_t *fv, GByteArray *bytes, guint offset, guint length)
+{
+ guint8* data;
+
+ if (fv->value.tvb) {
+ data = tvb_get_ptr(fv->value.tvb, offset, length);
+ g_byte_array_append(bytes, data, length);
+ }
+}
+
+void
+ftype_register_tvbuff(void)
+{
+
+ static ftype_t protocol_type = {
+ "FT_PROTOCOL",
+ "protocol",
+ 0,
+ value_new,
+ NULL,
+ NULL,
+ NULL,
+
+ value_set,
+ NULL,
+ NULL,
+
+ value_get,
+ NULL,
+ NULL,
+
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+
+ len,
+ slice,
+
+ };
+
+
+ ftype_register(FT_PROTOCOL, &protocol_type);
+}
diff --git a/epan/ftypes/ftypes-int.h b/epan/ftypes/ftypes-int.h
new file mode 100644
index 0000000000..4e6ce75bee
--- /dev/null
+++ b/epan/ftypes/ftypes-int.h
@@ -0,0 +1,60 @@
+#ifndef FTYPES_INT_H
+#define FTYPES_INT_H
+
+#include "packet.h"
+#include "ftypes.h"
+
+typedef void (*FtypeFromTvbuffFunc)(field_info*, tvbuff_t*, int, int, gboolean);
+typedef void (*FvalueNewFunc)(fvalue_t*);
+typedef void (*FvalueFreeFunc)(fvalue_t*);
+
+typedef gboolean (*FvalueFromString)(fvalue_t*, char*, LogFunc);
+
+typedef void (*FvalueSetFunc)(fvalue_t*, gpointer, gboolean);
+typedef void (*FvalueSetIntegerFunc)(fvalue_t*, guint32);
+typedef void (*FvalueSetFloatingFunc)(fvalue_t*, gdouble);
+
+typedef gpointer (*FvalueGetFunc)(fvalue_t*);
+typedef guint32 (*FvalueGetIntegerFunc)(fvalue_t*);
+typedef double (*FvalueGetFloatingFunc)(fvalue_t*);
+
+typedef gboolean (*FvalueCmp)(fvalue_t*, fvalue_t*);
+
+typedef guint (*FvalueLen)(fvalue_t*);
+typedef void (*FvalueSlice)(fvalue_t*, GByteArray *, guint, guint);
+
+struct _ftype_t {
+ const char *name;
+ const char *pretty_name;
+ int wire_size;
+ FvalueNewFunc new_value;
+ FvalueFreeFunc free_value;
+ FtypeFromTvbuffFunc from_tvbuff;
+ FvalueFromString val_from_string;
+
+ /* could be union */
+ FvalueSetFunc set_value;
+ FvalueSetIntegerFunc set_value_integer;
+ FvalueSetFloatingFunc set_value_floating;
+
+ /* could be union */
+ FvalueGetFunc get_value;
+ FvalueGetIntegerFunc get_value_integer;
+ FvalueGetFloatingFunc get_value_floating;
+
+ FvalueCmp cmp_eq;
+ FvalueCmp cmp_ne;
+ FvalueCmp cmp_gt;
+ FvalueCmp cmp_ge;
+ FvalueCmp cmp_lt;
+ FvalueCmp cmp_le;
+
+ FvalueLen len;
+ FvalueSlice slice;
+};
+
+
+void
+ftype_register(enum ftenum ftype, ftype_t *ft);
+
+#endif
diff --git a/epan/ftypes/ftypes.c b/epan/ftypes/ftypes.c
new file mode 100644
index 0000000000..7234008d53
--- /dev/null
+++ b/epan/ftypes/ftypes.c
@@ -0,0 +1,410 @@
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <ftypes-int.h>
+
+/* Keep track of ftype_t's via their ftenum number */
+static ftype_t* type_list[FT_NUM_TYPES];
+
+/* Space for quickly allocating/de-allocating fvalue_t's */
+static GMemChunk *gmc_fvalue = NULL;
+
+/* These are the ftype registration functions that need to be called.
+ * This list and the initialization function could be produced
+ * via a script, like the dissector registration, but there's so few
+ * that I don't mind doing it by hand for now. */
+void ftype_register_bytes(void);
+void ftype_register_double(void);
+void ftype_register_integers(void);
+void ftype_register_ipv4(void);
+void ftype_register_none(void);
+void ftype_register_string(void);
+void ftype_register_time(void);
+void ftype_register_tvbuff(void);
+
+/* Initialize the ftype module. */
+void
+ftypes_initialize(void)
+{
+ ftype_register_bytes();
+ ftype_register_double();
+ ftype_register_integers();
+ ftype_register_ipv4();
+ ftype_register_none();
+ ftype_register_string();
+ ftype_register_time();
+ ftype_register_tvbuff();
+
+ if (gmc_fvalue)
+ g_mem_chunk_destroy(gmc_fvalue);
+
+ gmc_fvalue = g_mem_chunk_new("gmc_fvalue", sizeof(fvalue_t),
+ 200 * sizeof(fvalue_t), G_ALLOC_AND_FREE);
+}
+
+void
+ftypes_cleanup(void)
+{
+ if (gmc_fvalue)
+ g_mem_chunk_destroy(gmc_fvalue);
+}
+
+
+
+/* Each ftype_t is registered via this function */
+void
+ftype_register(enum ftenum ftype, ftype_t *ft)
+{
+ /* Check input */
+ g_assert(ftype >= 0);
+ g_assert(ftype < FT_NUM_TYPES);
+
+ /* Don't re-register. */
+ g_assert(type_list[ftype] == NULL);
+
+ type_list[ftype] = ft;
+}
+
+/* Given an ftenum number, return an ftype_t* */
+static ftype_t*
+ftype_lookup(enum ftenum ftype)
+{
+ ftype_t* result;
+
+ /* Check input */
+ g_assert(ftype >= 0);
+ g_assert(ftype < FT_NUM_TYPES);
+
+ result = type_list[ftype];
+
+ /* Check output. */
+ g_assert(result != NULL);
+
+ return result;
+}
+
+
+/* Returns a string representing the name of the type. Useful
+ * for glossary production. */
+const char*
+ftype_name(enum ftenum ftype)
+{
+ ftype_t *ft;
+
+ ft = ftype_lookup(ftype);
+ return ft->name;
+}
+
+const char*
+ftype_pretty_name(enum ftenum ftype)
+{
+ ftype_t *ft;
+
+ ft = ftype_lookup(ftype);
+ return ft->pretty_name;
+}
+
+int
+ftype_length(enum ftenum ftype)
+{
+ ftype_t *ft;
+
+ ft = ftype_lookup(ftype);
+ return ft->wire_size;
+}
+
+gboolean
+ftype_can_slice(enum ftenum ftype)
+{
+ ftype_t *ft;
+
+ ft = ftype_lookup(ftype);
+ return ft->slice ? TRUE : FALSE;
+}
+
+gboolean
+ftype_can_eq(enum ftenum ftype)
+{
+ ftype_t *ft;
+
+ ft = ftype_lookup(ftype);
+ return ft->cmp_eq ? TRUE : FALSE;
+}
+
+gboolean
+ftype_can_ne(enum ftenum ftype)
+{
+ ftype_t *ft;
+
+ ft = ftype_lookup(ftype);
+ return ft->cmp_ne ? TRUE : FALSE;
+}
+
+gboolean
+ftype_can_gt(enum ftenum ftype)
+{
+ ftype_t *ft;
+
+ ft = ftype_lookup(ftype);
+ return ft->cmp_gt ? TRUE : FALSE;
+}
+
+gboolean
+ftype_can_ge(enum ftenum ftype)
+{
+ ftype_t *ft;
+
+ ft = ftype_lookup(ftype);
+ return ft->cmp_ge ? TRUE : FALSE;
+}
+
+gboolean
+ftype_can_lt(enum ftenum ftype)
+{
+ ftype_t *ft;
+
+ ft = ftype_lookup(ftype);
+ return ft->cmp_lt ? TRUE : FALSE;
+}
+
+gboolean
+ftype_can_le(enum ftenum ftype)
+{
+ ftype_t *ft;
+
+ ft = ftype_lookup(ftype);
+ return ft->cmp_le ? TRUE : FALSE;
+}
+
+/* ---------------------------------------------------------- */
+
+/* Allocate and initialize an fvalue_t, given an ftype */
+fvalue_t*
+fvalue_new(ftenum_t ftype)
+{
+ fvalue_t *fv;
+ ftype_t *ft;
+ FvalueNewFunc new_value;
+
+ fv = g_mem_chunk_alloc(gmc_fvalue);
+
+ ft = ftype_lookup(ftype);
+ fv->ftype = ft;
+
+ new_value = ft->new_value;
+ if (new_value) {
+ new_value(fv);
+ }
+
+ return fv;
+}
+
+/* Free all memory used by an fvalue_t */
+void
+fvalue_free(fvalue_t *fv)
+{
+ FvalueFreeFunc free_value;
+
+ free_value = fv->ftype->free_value;
+ if (free_value) {
+ free_value(fv);
+ }
+
+ g_mem_chunk_free(gmc_fvalue, fv);
+}
+
+
+
+fvalue_t*
+fvalue_from_string(ftenum_t ftype, char *s, LogFunc log)
+{
+ fvalue_t *fv;
+
+ fv = fvalue_new(ftype);
+ if (fv->ftype->val_from_string) {
+ if (fv->ftype->val_from_string(fv, s, log)) {
+ return fv;
+ }
+ }
+ else {
+ log("\"%s\" cannot be converted to %s.",
+ s, ftype_pretty_name(ftype));
+ }
+ fvalue_free(fv);
+ return NULL;
+}
+
+const char*
+fvalue_type_name(fvalue_t *fv)
+{
+ return fv->ftype->name;
+}
+
+
+guint
+fvalue_length(fvalue_t *fv)
+{
+ if (fv->ftype->len)
+ return fv->ftype->len(fv);
+ else
+ return fv->ftype->wire_size;
+}
+
+/* Returns a new FT_BYTES fvalue_t* if possible, otherwise NULL */
+fvalue_t*
+fvalue_slice(fvalue_t *fv, gint start, gint end)
+{
+ GByteArray *bytes;
+ guint data_length, abs_end;
+ guint offset=0, length=0;
+ fvalue_t *new_fv;
+
+ if (!fv->ftype->slice) {
+ return NULL;
+ }
+
+ data_length = fvalue_length(fv);
+ bytes = g_byte_array_new();
+
+ /* Find absolute start position (offset) */
+ if (start < 0) {
+ start = data_length + start;
+ if (start < 0) {
+ offset = 0;
+ }
+ else {
+ offset = start;
+ }
+ }
+ else {
+ offset = start;
+ }
+
+ /* Limit the offset value */
+ if (offset > data_length) {
+ offset = data_length;
+ }
+
+ /* Find absolute end position (abs_end) */
+ if (end < 0) {
+ end = data_length + end;
+ if (end < 0) {
+ abs_end = 0;
+ }
+ else {
+ abs_end = end;
+ }
+ }
+ else {
+ abs_end = end;
+ }
+
+ /* Limit the abs_end value */
+ if (abs_end > data_length) {
+ abs_end = data_length;
+ }
+
+ /* Does end position occur *after* start position? */
+ if (abs_end > offset) {
+ length = abs_end - offset;
+ fv->ftype->slice(fv, bytes, offset, length);
+ }
+
+ new_fv = fvalue_new(FT_BYTES);
+ fvalue_set(new_fv, bytes, TRUE);
+ return new_fv;
+}
+
+
+void
+fvalue_set(fvalue_t *fv, gpointer value, gboolean already_copied)
+{
+ g_assert(fv->ftype->set_value);
+ fv->ftype->set_value(fv, value, already_copied);
+}
+
+void
+fvalue_set_integer(fvalue_t *fv, guint32 value)
+{
+ g_assert(fv->ftype->set_value_integer);
+ fv->ftype->set_value_integer(fv, value);
+}
+
+void
+fvalue_set_floating(fvalue_t *fv, gdouble value)
+{
+ g_assert(fv->ftype->set_value_floating);
+ fv->ftype->set_value_floating(fv, value);
+}
+
+
+gpointer
+fvalue_get(fvalue_t *fv)
+{
+ g_assert(fv->ftype->get_value);
+ return fv->ftype->get_value(fv);
+}
+
+guint32
+fvalue_get_integer(fvalue_t *fv)
+{
+ g_assert(fv->ftype->get_value_integer);
+ return fv->ftype->get_value_integer(fv);
+}
+
+double
+fvalue_get_floating(fvalue_t *fv)
+{
+ g_assert(fv->ftype->get_value_floating);
+ return fv->ftype->get_value_floating(fv);
+}
+
+gboolean
+fvalue_eq(fvalue_t *a, fvalue_t *b)
+{
+ /* XXX - check compatibility of a and b */
+ g_assert(a->ftype->cmp_eq);
+ return a->ftype->cmp_eq(a, b);
+}
+
+gboolean
+fvalue_ne(fvalue_t *a, fvalue_t *b)
+{
+ /* XXX - check compatibility of a and b */
+ g_assert(a->ftype->cmp_ne);
+ return a->ftype->cmp_ne(a, b);
+}
+
+gboolean
+fvalue_gt(fvalue_t *a, fvalue_t *b)
+{
+ /* XXX - check compatibility of a and b */
+ g_assert(a->ftype->cmp_gt);
+ return a->ftype->cmp_gt(a, b);
+}
+
+gboolean
+fvalue_ge(fvalue_t *a, fvalue_t *b)
+{
+ /* XXX - check compatibility of a and b */
+ g_assert(a->ftype->cmp_ge);
+ return a->ftype->cmp_ge(a, b);
+}
+
+gboolean
+fvalue_lt(fvalue_t *a, fvalue_t *b)
+{
+ /* XXX - check compatibility of a and b */
+ g_assert(a->ftype->cmp_lt);
+ return a->ftype->cmp_lt(a, b);
+}
+
+gboolean
+fvalue_le(fvalue_t *a, fvalue_t *b)
+{
+ /* XXX - check compatibility of a and b */
+ g_assert(a->ftype->cmp_le);
+ return a->ftype->cmp_le(a, b);
+}
diff --git a/epan/ftypes/ftypes.h b/epan/ftypes/ftypes.h
new file mode 100644
index 0000000000..1431f35427
--- /dev/null
+++ b/epan/ftypes/ftypes.h
@@ -0,0 +1,197 @@
+/* ftypes.h
+ * Definitions for field types
+ *
+ * $Id: ftypes.h,v 1.1 2001/02/01 20:21:19 gram Exp $
+ *
+ * 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 FTYPES_H
+#define FTYPES_H
+
+#include <glib.h>
+
+
+/* field types */
+enum ftenum {
+ FT_NONE, /* used for text labels with no value */
+ FT_PROTOCOL,
+ FT_BOOLEAN, /* TRUE and FALSE come from <glib.h> */
+ FT_UINT8,
+ FT_UINT16,
+ FT_UINT24, /* really a UINT32, but displayed as 3 hex-digits if FD_HEX*/
+ FT_UINT32,
+ FT_INT8,
+ FT_INT16,
+ FT_INT24,
+ FT_INT32,
+ FT_DOUBLE,
+ FT_ABSOLUTE_TIME,
+ FT_RELATIVE_TIME,
+ FT_STRING,
+ FT_STRINGZ, /* for use with proto_tree_add_item() */
+ FT_UINT_STRING, /* for use with proto_tree_add_item() */
+ FT_ETHER,
+ FT_BYTES,
+ FT_IPv4,
+ FT_IPv6,
+ FT_IPXNET,
+/* FT_TEXT_ONLY,*/ /* non-filterable, used when converting ethereal
+ from old-style proto_tree to new-style proto_tree */
+ FT_NUM_TYPES /* last item number plus one */
+};
+
+typedef enum ftenum ftenum_t;
+typedef struct _ftype_t ftype_t;
+
+/* Initialize the ftypes subsytem. Called once. */
+void
+ftypes_initialize(void);
+
+/* Cleanup the ftypes subsystem. Called once. */
+void
+ftypes_cleanup(void);
+
+
+/* ---------------- FTYPE ----------------- */
+
+/* Return a string representing the name of the type */
+const char*
+ftype_name(ftenum_t ftype);
+
+/* Return a string presenting a "pretty" representation of the
+ * name of the type. The pretty name means more to the user than
+ * that "FT_*" name. */
+const char*
+ftype_pretty_name(ftenum_t ftype);
+
+/* Returns length of field in packet, or 0 if not determinable/defined. */
+int
+ftype_length(ftenum_t ftype);
+
+gboolean
+ftype_can_slice(enum ftenum ftype);
+
+gboolean
+ftype_can_eq(enum ftenum ftype);
+
+gboolean
+ftype_can_ne(enum ftenum ftype);
+
+gboolean
+ftype_can_gt(enum ftenum ftype);
+
+gboolean
+ftype_can_ge(enum ftenum ftype);
+
+gboolean
+ftype_can_lt(enum ftenum ftype);
+
+gboolean
+ftype_can_le(enum ftenum ftype);
+
+/* ---------------- FVALUE ----------------- */
+
+#include "ipv4.h"
+
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+
+#ifdef HAVE_WINSOCK_H
+#include <winsock.h>
+#endif
+
+#include "tvbuff.h"
+
+typedef struct {
+ ftype_t *ftype;
+ union {
+ /* Put a few basic types in here */
+ gpointer pointer;
+ guint32 integer;
+ gdouble floating;
+ gchar *string;
+ GByteArray *bytes;
+ ipv4_addr ipv4;
+ guint8 ipv6[16];
+ struct timeval time;
+ tvbuff_t *tvb;
+ } value;
+} fvalue_t;
+
+fvalue_t*
+fvalue_new(ftenum_t ftype);
+
+void
+fvalue_free(fvalue_t *fv);
+
+typedef void (*LogFunc)(char*,...);
+
+fvalue_t*
+fvalue_from_string(ftenum_t ftype, char *s, LogFunc log);
+
+const char*
+fvalue_type_name(fvalue_t *fv);
+
+void
+fvalue_set(fvalue_t *fv, gpointer value, gboolean already_copied);
+
+void
+fvalue_set_integer(fvalue_t *fv, guint32 value);
+
+void
+fvalue_set_floating(fvalue_t *fv, gdouble value);
+
+gpointer
+fvalue_get(fvalue_t *fv);
+
+guint32
+fvalue_get_integer(fvalue_t *fv);
+
+double
+fvalue_get_floating(fvalue_t *fv);
+
+gboolean
+fvalue_eq(fvalue_t *a, fvalue_t *b);
+
+gboolean
+fvalue_ne(fvalue_t *a, fvalue_t *b);
+
+gboolean
+fvalue_gt(fvalue_t *a, fvalue_t *b);
+
+gboolean
+fvalue_ge(fvalue_t *a, fvalue_t *b);
+
+gboolean
+fvalue_lt(fvalue_t *a, fvalue_t *b);
+
+gboolean
+fvalue_le(fvalue_t *a, fvalue_t *b);
+
+guint
+fvalue_length(fvalue_t *fv);
+
+fvalue_t*
+fvalue_slice(fvalue_t *fv, gint start, gint end);
+
+#endif /* ftypes.h */
diff --git a/epan/gdebug.h b/epan/gdebug.h
new file mode 100644
index 0000000000..230931fbf8
--- /dev/null
+++ b/epan/gdebug.h
@@ -0,0 +1,38 @@
+/* $Id: gdebug.h,v 1.1 2001/02/01 20:21:16 gram Exp $ */
+
+#ifndef GDEBUG_H
+#define GDEBUG_H
+
+#ifdef __GNUC__
+
+/* The last "%s" in g_log() is for the empty-string arg that
+ * g_debug() always passes. */
+#define _g_debug(format, args...) \
+ g_log(G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, \
+ "%s():%s +%d: " format "%s", \
+ G_GNUC_PRETTY_FUNCTION, __FILE__, __LINE__, ##args) ;
+
+/* Always pass a empty-string argument to _g_debug() so that g_debug will always
+ * have at least 2 arguments. If user passes 1 arg to g_debug() (i.e., only
+ * a format string), _g_debug() will still work. */
+#define g_debug(args...) \
+ _g_debug(args, "")
+
+
+#else
+
+#include <stdio.h>
+#include <stdarg.h>
+
+static void
+g_debug(const char* format, ...)
+{
+ va_list args;
+ va_start(args, format);
+ vfprintf(stderr, format, args);
+ va_end(args);
+}
+
+#endif /* __GNUC__ */
+
+#endif /* GDEBUG_H */
diff --git a/epan/ipv4.h b/epan/ipv4.h
index 8154465cfb..20728bd56d 100644
--- a/epan/ipv4.h
+++ b/epan/ipv4.h
@@ -5,7 +5,7 @@
*
* Gilbert Ramirez <gram@xiexie.org>
*
- * $Id: ipv4.h,v 1.1 2000/09/28 03:52:12 gram Exp $
+ * $Id: ipv4.h,v 1.2 2001/02/01 20:21:16 gram Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@zing.org>
@@ -30,6 +30,8 @@
#ifndef __IPV4_H__
#define __IPV4_H__
+#include <glib.h>
+
typedef struct {
guint32 addr; /* stored in host order */
guint32 nmask; /* stored in host order */
diff --git a/epan/proto.c b/epan/proto.c
index fd45be0eae..29df3f68bc 100644
--- a/epan/proto.c
+++ b/epan/proto.c
@@ -1,7 +1,7 @@
/* proto.c
* Routines for protocol tree
*
- * $Id: proto.c,v 1.6 2001/02/01 07:34:30 guy Exp $
+ * $Id: proto.c,v 1.7 2001/02/01 20:21:16 gram Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@zing.org>
@@ -60,7 +60,7 @@ static void fill_label_numeric_bitfield(field_info *fi, gchar *label_str);
static void fill_label_int(field_info *fi, gchar *label_str);
static void fill_label_enumerated_int(field_info *fi, gchar *label_str);
-static int hfinfo_bitwidth(header_field_info *hfinfo);
+int hfinfo_bitwidth(header_field_info *hfinfo);
static char* hfinfo_uint_vals_format(header_field_info *hfinfo);
static char* hfinfo_uint_format(header_field_info *hfinfo);
static char* hfinfo_int_vals_format(header_field_info *hfinfo);
@@ -166,7 +166,7 @@ proto_init(const char *plugin_dir)
{
static hf_register_info hf[] = {
{ &hf_text_only,
- { "Text", "text", FT_TEXT_ONLY, BASE_NONE, NULL, 0x0,
+ { "Text", "text", FT_NONE, BASE_NONE, NULL, 0x0,
"" }},
};
@@ -182,8 +182,7 @@ proto_init(const char *plugin_dir)
g_free(tree_is_expanded);
gmc_hfinfo = g_mem_chunk_new("gmc_hfinfo",
- sizeof(struct header_field_info), 50 * sizeof(struct
- header_field_info), G_ALLOC_ONLY);
+ sizeof(header_field_info), 50 * sizeof(header_field_info), G_ALLOC_ONLY);
gmc_field_info = g_mem_chunk_new("gmc_field_info",
sizeof(struct field_info), 200 * sizeof(struct field_info),
G_ALLOC_AND_FREE);
@@ -198,6 +197,9 @@ proto_init(const char *plugin_dir)
tree_is_expanded[0] = FALSE;
num_tree_types = 1;
+ /* Initialize the ftype subsystem */
+ ftypes_initialize();
+
/* Have each built-in dissector register its protocols, fields,
dissector tables, and dissectors to be called through a
handle, and do whatever one-time initialization it needs to
@@ -241,6 +243,9 @@ proto_cleanup(void)
g_mem_chunk_destroy(gmc_item_labels);
if (gpa_hfinfo)
g_ptr_array_free(gpa_hfinfo, FALSE);
+
+ /* Cleanup the ftype subsystem */
+ ftypes_cleanup();
}
/* frees the resources that the dissection a proto_tree uses */
@@ -265,23 +270,17 @@ proto_tree_free_node(GNode *node, gpointer data)
field_info *fi = (field_info*) (node->data);
if (fi != NULL) {
- if (fi->representation)
+ if (fi->representation) {
g_mem_chunk_free(gmc_item_labels, fi->representation);
- if (fi->hfinfo->type == FT_STRING)
- g_free(fi->value.string);
- else if (fi->hfinfo->type == FT_STRINGZ)
- g_free(fi->value.string);
- else if (fi->hfinfo->type == FT_UINT_STRING)
- g_free(fi->value.string);
- else if (fi->hfinfo->type == FT_BYTES)
- g_free(fi->value.bytes);
+ }
+ fvalue_free(fi->value);
free_field_info(fi);
}
return FALSE; /* FALSE = do not end traversal of GNode tree */
}
/* Finds a record in the hf_info_records array by id. */
-struct header_field_info*
+header_field_info*
proto_registrar_get_nth(int hfindex)
{
g_assert(hfindex >= 0 && hfindex < gpa_hfinfo->len);
@@ -458,6 +457,10 @@ proto_tree_add_item(proto_tree *tree, int hfindex, tvbuff_t *tvb,
/* no value to set for FT_NONE */
break;
+ case FT_PROTOCOL:
+ proto_tree_set_protocol_tvb(new_fi, tvb);
+ break;
+
case FT_BYTES:
proto_tree_set_bytes_tvb(new_fi, tvb, start, length);
break;
@@ -542,7 +545,7 @@ proto_tree_add_item(proto_tree *tree, int hfindex, tvbuff_t *tvb,
default:
g_error("new_fi->hfinfo->type %d (%s) not handled\n",
new_fi->hfinfo->type,
- proto_registrar_ftype_name(new_fi->hfinfo->type));
+ ftype_name(new_fi->hfinfo->type));
g_assert_not_reached();
break;
@@ -576,7 +579,7 @@ proto_tree_add_item_hidden(proto_tree *tree, int hfindex, tvbuff_t *tvb,
/* Add a FT_NONE to a proto_tree */
proto_item *
-proto_tree_add_protocol_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start,
+proto_tree_add_none_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start,
gint length, const char *format, ...)
{
proto_item *pi;
@@ -596,10 +599,48 @@ proto_tree_add_protocol_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gin
va_end(ap);
/* no value to set for FT_NONE */
+ return pi;
+}
+
+
+static void
+proto_tree_set_protocol_tvb(field_info *fi, tvbuff_t *tvb)
+{
+ fvalue_set(fi->value, tvb, TRUE);
+}
+
+/* Add a FT_PROTOCOL to a proto_tree */
+proto_item *
+proto_tree_add_protocol_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start,
+ gint length, const char *format, ...)
+{
+ proto_item *pi;
+ va_list ap;
+ header_field_info *hfinfo;
+ field_info *new_fi;
+
+ if (!tree)
+ return (NULL);
+ hfinfo = proto_registrar_get_nth(hfindex);
+ g_assert(hfinfo->type == FT_PROTOCOL);
+
+ pi = proto_tree_add_pi(tree, hfindex, tvb, start, length, &new_fi);
+
+ va_start(ap, format);
+ proto_tree_set_representation(pi, format, ap);
+ va_end(ap);
+
+ if (start == 0) {
+ proto_tree_set_protocol_tvb(new_fi, tvb);
+ }
+ else {
+ proto_tree_set_protocol_tvb(new_fi, NULL);
+ }
return pi;
}
+
/* Add a FT_BYTES to a proto_tree */
proto_item *
proto_tree_add_bytes(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start,
@@ -656,34 +697,23 @@ proto_tree_add_bytes_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint s
return pi;
}
-/* Set the FT_BYTES value */
static void
proto_tree_set_bytes(field_info *fi, const guint8* start_ptr, gint length)
{
- g_assert(start_ptr != NULL);
+ GByteArray *bytes;
+ bytes = g_byte_array_new();
if (length > 0) {
- /* This g_malloc'ed memory is freed in
- proto_tree_free_node() */
- fi->value.bytes = g_malloc(length);
- memcpy(fi->value.bytes, start_ptr, length);
- }
- else {
- fi->value.bytes = NULL;
+ g_byte_array_append(bytes, start_ptr, length);
}
+ fvalue_set(fi->value, bytes, TRUE);
}
+
static void
proto_tree_set_bytes_tvb(field_info *fi, tvbuff_t *tvb, gint offset, gint length)
{
- if (length > 0) {
- /* This g_malloc'ed memory is freed in
- proto_tree_free_node() */
- fi->value.bytes = tvb_memdup(tvb, offset, length);
- }
- else {
- fi->value.bytes = NULL;
- }
+ proto_tree_set_bytes(fi, tvb_get_ptr(tvb, offset, length), length);
}
/* Add a FT_*TIME to a proto_tree */
@@ -747,7 +777,7 @@ proto_tree_add_time_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint st
static void
proto_tree_set_time(field_info *fi, struct timeval *value_ptr)
{
- memcpy(&fi->value.time, value_ptr, sizeof(struct timeval));
+ fvalue_set(fi->value, value_ptr, FALSE);
}
/* Add a FT_IPXNET to a proto_tree */
@@ -810,7 +840,7 @@ proto_tree_add_ipxnet_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint
static void
proto_tree_set_ipxnet(field_info *fi, guint32 value)
{
- fi->value.numeric = value;
+ fvalue_set_integer(fi->value, value);
}
/* Add a FT_IPv4 to a proto_tree */
@@ -873,8 +903,7 @@ proto_tree_add_ipv4_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint st
static void
proto_tree_set_ipv4(field_info *fi, guint32 value)
{
- ipv4_addr_set_net_order_addr(&(fi->value.ipv4), value);
- ipv4_addr_set_netmask_bits(&(fi->value.ipv4), 32);
+ fvalue_set_integer(fi->value, value);
}
/* Add a FT_IPv6 to a proto_tree */
@@ -937,13 +966,13 @@ proto_tree_add_ipv6_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint st
static void
proto_tree_set_ipv6(field_info *fi, const guint8* value_ptr)
{
- memcpy(fi->value.ipv6, value_ptr, 16);
+ fvalue_set(fi->value, (gpointer) value_ptr, FALSE);
}
static void
proto_tree_set_ipv6_tvb(field_info *fi, tvbuff_t *tvb, gint start)
{
- tvb_memcpy(tvb, fi->value.ipv6, start, 16);
+ proto_tree_set_ipv6(fi, tvb_get_ptr(tvb, start, 16));
}
/* Add a FT_STRING to a proto_tree */
@@ -1006,17 +1035,19 @@ proto_tree_add_string_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint
static void
proto_tree_set_string(field_info *fi, const char* value)
{
- /* This g_strdup'ed memory is freed in proto_tree_free_node() */
- fi->value.string = g_strdup(value);
+ fvalue_set(fi->value, (gpointer) value, FALSE);
}
static void
proto_tree_set_string_tvb(field_info *fi, tvbuff_t *tvb, gint start, gint length)
{
+ gchar *string;
+
/* This memory is freed in proto_tree_free_node() */
- fi->value.string = g_malloc(length + 1);
- tvb_memcpy(tvb, fi->value.string, start, length);
- fi->value.string[length] = '\0';
+ string = g_malloc(length + 1);
+ tvb_memcpy(tvb, string, start, length);
+ string[length] = '\0';
+ fvalue_set(fi->value, string, TRUE);
}
/* Add a FT_ETHER to a proto_tree */
@@ -1079,13 +1110,13 @@ proto_tree_add_ether_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint s
static void
proto_tree_set_ether(field_info *fi, const guint8* value)
{
- memcpy(fi->value.ether, value, 6);
+ fvalue_set(fi->value, (gpointer) value, FALSE);
}
static void
proto_tree_set_ether_tvb(field_info *fi, tvbuff_t *tvb, gint start)
{
- tvb_memcpy(tvb, fi->value.ether, start, 6);
+ proto_tree_set_ether(fi, tvb_get_ptr(tvb, start, 6));
}
/* Add a FT_BOOLEAN to a proto_tree */
@@ -1146,7 +1177,7 @@ proto_tree_add_boolean_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint
/* Set the FT_BOOLEAN value */
static void
-proto_tree_set_boolean(field_info *fi, guint32 value)
+proto_tree_set_boolean(field_info *fi, guint32 value)
{
proto_tree_set_uint(fi, value);
}
@@ -1211,7 +1242,7 @@ proto_tree_add_double_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint
static void
proto_tree_set_double(field_info *fi, double value)
{
- fi->value.floating = value;
+ fvalue_set_floating(fi->value, value);
}
/* Add any FT_UINT* to a proto_tree */
@@ -1283,19 +1314,22 @@ proto_tree_add_uint_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint st
static void
proto_tree_set_uint(field_info *fi, guint32 value)
{
- header_field_info *hfinfo;
+ header_field_info *hfinfo;
+ guint32 integer;
hfinfo = fi->hfinfo;
- fi->value.numeric = value;
+ integer = value;
+
if (hfinfo->bitmask) {
/* Mask out irrelevant portions */
- fi->value.numeric &= hfinfo->bitmask;
+ integer &= hfinfo->bitmask;
/* Shift bits */
if (hfinfo->bitshift > 0) {
- fi->value.numeric >>= hfinfo->bitshift;
+ integer >>= hfinfo->bitshift;
}
}
+ fvalue_set_integer(fi->value, integer);
}
/* Add any FT_INT* to a proto_tree */
@@ -1367,19 +1401,22 @@ proto_tree_add_int_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint sta
static void
proto_tree_set_int(field_info *fi, gint32 value)
{
- header_field_info *hfinfo;
+ header_field_info *hfinfo;
+ guint32 integer;
hfinfo = fi->hfinfo;
- fi->value.numeric = (guint32) value;
+ integer = (guint32) value;
+
if (hfinfo->bitmask) {
/* Mask out irrelevant portions */
- fi->value.numeric &= hfinfo->bitmask;
+ integer &= hfinfo->bitmask;
/* Shift bits */
if (hfinfo->bitshift > 0) {
- fi->value.numeric >>= hfinfo->bitshift;
+ integer >>= hfinfo->bitshift;
}
}
+ fvalue_set_integer(fi->value, integer);
}
@@ -1437,6 +1474,8 @@ alloc_field_info(int hfindex, tvbuff_t *tvb, gint start, gint length)
fi->visible = proto_tree_is_visible;
fi->representation = NULL;
+ fi->value = fvalue_new(fi->hfinfo->type);
+
return fi;
}
@@ -1508,7 +1547,7 @@ int
proto_register_protocol(char *name, char *short_name, char *filter_name)
{
protocol_t *protocol;
- struct header_field_info *hfinfo;
+ header_field_info *hfinfo;
int proto_id;
/* Add this protocol to the list of known protocols; the list
@@ -1528,7 +1567,7 @@ proto_register_protocol(char *name, char *short_name, char *filter_name)
hfinfo = g_mem_chunk_alloc(gmc_hfinfo);
hfinfo->name = name;
hfinfo->abbrev = filter_name;
- hfinfo->type = FT_NONE;
+ hfinfo->type = FT_PROTOCOL;
hfinfo->strings = NULL;
hfinfo->bitmask = 0;
hfinfo->bitshift = 0;
@@ -1735,6 +1774,7 @@ proto_register_field_init(header_field_info *hfinfo, int parent)
}
hfinfo->parent = parent;
+ hfinfo->same_name = NULL;
/* if we always add and never delete, then id == len - 1 is correct */
g_ptr_array_add(gpa_hfinfo, hfinfo);
@@ -1770,11 +1810,16 @@ proto_register_subtree_array(gint **indices, int num_indices)
void
proto_item_fill_label(field_info *fi, gchar *label_str)
{
- struct header_field_info *hfinfo = fi->hfinfo;
+ header_field_info *hfinfo = fi->hfinfo;
+
+ guint8 *bytes;
+ guint32 integer;
+ ipv4_addr *ipv4;
guint32 n_addr; /* network-order IPv4 address */
switch(hfinfo->type) {
case FT_NONE:
+ case FT_PROTOCOL:
snprintf(label_str, ITEM_LABEL_LENGTH,
"%s", hfinfo->name);
break;
@@ -1784,10 +1829,11 @@ proto_item_fill_label(field_info *fi, gchar *label_str)
break;
case FT_BYTES:
- if (fi->value.bytes) {
+ bytes = fvalue_get(fi->value);
+ if (bytes) {
snprintf(label_str, ITEM_LABEL_LENGTH,
"%s: %s", hfinfo->name,
- bytes_to_str(fi->value.bytes, fi->length));
+ bytes_to_str(bytes, fi->length));
}
else {
snprintf(label_str, ITEM_LABEL_LENGTH,
@@ -1838,37 +1884,39 @@ proto_item_fill_label(field_info *fi, gchar *label_str)
case FT_DOUBLE:
snprintf(label_str, ITEM_LABEL_LENGTH,
- "%s: %g", hfinfo->name,
- fi->value.floating);
+ "%s: %g", hfinfo->name, fvalue_get_floating(fi->value));
break;
case FT_ABSOLUTE_TIME:
snprintf(label_str, ITEM_LABEL_LENGTH,
"%s: %s", hfinfo->name,
- abs_time_to_str(&fi->value.time));
+ abs_time_to_str(fvalue_get(fi->value)));
break;
case FT_RELATIVE_TIME:
snprintf(label_str, ITEM_LABEL_LENGTH,
"%s: %s seconds", hfinfo->name,
- rel_time_to_str(&fi->value.time));
+ rel_time_to_str(fvalue_get(fi->value)));
break;
case FT_IPXNET:
+ integer = fvalue_get_integer(fi->value);
snprintf(label_str, ITEM_LABEL_LENGTH,
"%s: 0x%08X (%s)", hfinfo->name,
- fi->value.numeric, get_ipxnet_name(fi->value.numeric));
+ integer, get_ipxnet_name(integer));
break;
case FT_ETHER:
+ bytes = fvalue_get(fi->value);
snprintf(label_str, ITEM_LABEL_LENGTH,
"%s: %s (%s)", hfinfo->name,
- ether_to_str(fi->value.ether),
- get_ether_name(fi->value.ether));
+ ether_to_str(bytes),
+ get_ether_name(bytes));
break;
case FT_IPv4:
- n_addr = ipv4_get_net_order_addr(&fi->value.ipv4);
+ ipv4 = fvalue_get(fi->value);
+ n_addr = ipv4_get_net_order_addr(ipv4);
snprintf(label_str, ITEM_LABEL_LENGTH,
"%s: %s (%s)", hfinfo->name,
get_hostname(n_addr),
@@ -1876,23 +1924,24 @@ proto_item_fill_label(field_info *fi, gchar *label_str)
break;
case FT_IPv6:
+ bytes = fvalue_get(fi->value);
snprintf(label_str, ITEM_LABEL_LENGTH,
"%s: %s (%s)", hfinfo->name,
- get_hostname6((struct e_in6_addr *)fi->value.ipv6),
- ip6_to_str((struct e_in6_addr*)fi->value.ipv6));
+ get_hostname6((struct e_in6_addr *)bytes),
+ ip6_to_str((struct e_in6_addr*)bytes));
break;
case FT_STRING:
case FT_STRINGZ:
case FT_UINT_STRING:
snprintf(label_str, ITEM_LABEL_LENGTH,
- "%s: %s", hfinfo->name, fi->value.string);
+ "%s: %s", hfinfo->name, (char*) fvalue_get(fi->value));
break;
default:
g_error("hfinfo->type %d (%s) not handled\n",
hfinfo->type,
- proto_registrar_ftype_name(hfinfo->type));
+ ftype_name(hfinfo->type));
g_assert_not_reached();
break;
}
@@ -1901,24 +1950,26 @@ proto_item_fill_label(field_info *fi, gchar *label_str)
static void
fill_label_boolean(field_info *fi, gchar *label_str)
{
- char *p = label_str;
- int bitfield_byte_length = 0, bitwidth;
- guint32 unshifted_value;
+ char *p = label_str;
+ int bitfield_byte_length = 0, bitwidth;
+ guint32 unshifted_value;
+ guint32 value;
- struct header_field_info *hfinfo = fi->hfinfo;
- struct true_false_string default_tf = { "True", "False" };
- struct true_false_string *tfstring = &default_tf;
+ header_field_info *hfinfo = fi->hfinfo;
+ static true_false_string default_tf = { "True", "False" };
+ true_false_string *tfstring = &default_tf;
if (hfinfo->strings) {
tfstring = (struct true_false_string*) hfinfo->strings;
}
+ value = fvalue_get_integer(fi->value);
if (hfinfo->bitmask) {
/* Figure out the bit width */
bitwidth = hfinfo_bitwidth(hfinfo);
/* Un-shift bits */
- unshifted_value = fi->value.numeric;
+ unshifted_value = value;
if (hfinfo->bitshift > 0) {
unshifted_value <<= hfinfo->bitshift;
}
@@ -1931,7 +1982,7 @@ fill_label_boolean(field_info *fi, gchar *label_str)
/* Fill in the textual info */
snprintf(p, ITEM_LABEL_LENGTH - bitfield_byte_length,
"%s: %s", hfinfo->name,
- fi->value.numeric ? tfstring->true_string : tfstring->false_string);
+ value ? tfstring->true_string : tfstring->false_string);
}
@@ -1942,8 +1993,9 @@ fill_label_enumerated_bitfield(field_info *fi, gchar *label_str)
char *format = NULL, *p;
int bitfield_byte_length, bitwidth;
guint32 unshifted_value;
+ guint32 value;
- struct header_field_info *hfinfo = fi->hfinfo;
+ header_field_info *hfinfo = fi->hfinfo;
/* Figure out the bit width */
bitwidth = hfinfo_bitwidth(hfinfo);
@@ -1952,7 +2004,8 @@ fill_label_enumerated_bitfield(field_info *fi, gchar *label_str)
format = hfinfo_uint_vals_format(hfinfo);
/* Un-shift bits */
- unshifted_value = fi->value.numeric;
+ unshifted_value = fvalue_get_integer(fi->value);
+ value = unshifted_value;
if (hfinfo->bitshift > 0) {
unshifted_value <<= hfinfo->bitshift;
}
@@ -1964,8 +2017,7 @@ fill_label_enumerated_bitfield(field_info *fi, gchar *label_str)
/* Fill in the textual info using stored (shifted) value */
snprintf(p, ITEM_LABEL_LENGTH - bitfield_byte_length,
format, hfinfo->name,
- val_to_str(fi->value.numeric, cVALS(hfinfo->strings), "Unknown"),
- fi->value.numeric);
+ val_to_str(value, cVALS(hfinfo->strings), "Unknown"), value);
}
static void
@@ -1974,8 +2026,9 @@ fill_label_numeric_bitfield(field_info *fi, gchar *label_str)
char *format = NULL, *p;
int bitfield_byte_length, bitwidth;
guint32 unshifted_value;
+ guint32 value;
- struct header_field_info *hfinfo = fi->hfinfo;
+ header_field_info *hfinfo = fi->hfinfo;
/* Figure out the bit width */
bitwidth = hfinfo_bitwidth(hfinfo);
@@ -1984,7 +2037,8 @@ fill_label_numeric_bitfield(field_info *fi, gchar *label_str)
format = hfinfo_uint_format(hfinfo);
/* Un-shift bits */
- unshifted_value = fi->value.numeric;
+ unshifted_value = fvalue_get_integer(fi->value);
+ value = unshifted_value;
if (hfinfo->bitshift > 0) {
unshifted_value <<= hfinfo->bitshift;
}
@@ -1995,70 +2049,77 @@ fill_label_numeric_bitfield(field_info *fi, gchar *label_str)
/* Fill in the textual info using stored (shifted) value */
snprintf(p, ITEM_LABEL_LENGTH - bitfield_byte_length,
- format, hfinfo->name, fi->value.numeric);
+ format, hfinfo->name, value);
}
static void
fill_label_enumerated_uint(field_info *fi, gchar *label_str)
{
char *format = NULL;
- struct header_field_info *hfinfo = fi->hfinfo;
+ header_field_info *hfinfo = fi->hfinfo;
+ guint32 value;
/* Pick the proper format string */
format = hfinfo_uint_vals_format(hfinfo);
+ value = fvalue_get_integer(fi->value);
+
/* Fill in the textual info */
snprintf(label_str, ITEM_LABEL_LENGTH,
format, hfinfo->name,
- val_to_str(fi->value.numeric, cVALS(hfinfo->strings), "Unknown"),
- fi->value.numeric);
+ val_to_str(value, cVALS(hfinfo->strings), "Unknown"), value);
}
static void
fill_label_uint(field_info *fi, gchar *label_str)
{
char *format = NULL;
- struct header_field_info *hfinfo = fi->hfinfo;
+ header_field_info *hfinfo = fi->hfinfo;
+ guint32 value;
/* Pick the proper format string */
format = hfinfo_uint_format(hfinfo);
+ value = fvalue_get_integer(fi->value);
/* Fill in the textual info */
snprintf(label_str, ITEM_LABEL_LENGTH,
- format, hfinfo->name, fi->value.numeric);
+ format, hfinfo->name, value);
}
static void
fill_label_enumerated_int(field_info *fi, gchar *label_str)
{
char *format = NULL;
- struct header_field_info *hfinfo = fi->hfinfo;
+ header_field_info *hfinfo = fi->hfinfo;
+ guint32 value;
/* Pick the proper format string */
format = hfinfo_int_vals_format(hfinfo);
+ value = fvalue_get_integer(fi->value);
/* Fill in the textual info */
snprintf(label_str, ITEM_LABEL_LENGTH,
format, hfinfo->name,
- val_to_str(fi->value.numeric, cVALS(hfinfo->strings), "Unknown"),
- fi->value.numeric);
+ val_to_str(value, cVALS(hfinfo->strings), "Unknown"), value);
}
static void
fill_label_int(field_info *fi, gchar *label_str)
{
char *format = NULL;
- struct header_field_info *hfinfo = fi->hfinfo;
+ header_field_info *hfinfo = fi->hfinfo;
+ guint32 value;
/* Pick the proper format string */
format = hfinfo_int_format(hfinfo);
+ value = fvalue_get_integer(fi->value);
/* Fill in the textual info */
snprintf(label_str, ITEM_LABEL_LENGTH,
- format, hfinfo->name, fi->value.numeric);
+ format, hfinfo->name, value);
}
-static int
+int
hfinfo_bitwidth(header_field_info *hfinfo)
{
int bitwidth = 0;
@@ -2267,7 +2328,7 @@ proto_registrar_n(void)
char*
proto_registrar_get_name(int n)
{
- struct header_field_info *hfinfo;
+ header_field_info *hfinfo;
hfinfo = proto_registrar_get_nth(n);
if (hfinfo)
return hfinfo->name;
@@ -2277,7 +2338,7 @@ proto_registrar_get_name(int n)
char*
proto_registrar_get_abbrev(int n)
{
- struct header_field_info *hfinfo;
+ header_field_info *hfinfo;
hfinfo = proto_registrar_get_nth(n);
if (hfinfo)
@@ -2289,7 +2350,7 @@ proto_registrar_get_abbrev(int n)
int
proto_registrar_get_ftype(int n)
{
- struct header_field_info *hfinfo;
+ header_field_info *hfinfo;
hfinfo = proto_registrar_get_nth(n);
if (hfinfo)
@@ -2301,7 +2362,7 @@ proto_registrar_get_ftype(int n)
int
proto_registrar_get_parent(int n)
{
- struct header_field_info *hfinfo;
+ header_field_info *hfinfo;
hfinfo = proto_registrar_get_nth(n);
if (hfinfo)
@@ -2313,7 +2374,7 @@ proto_registrar_get_parent(int n)
gboolean
proto_registrar_is_protocol(int n)
{
- struct header_field_info *hfinfo;
+ header_field_info *hfinfo;
hfinfo = proto_registrar_get_nth(n);
if (hfinfo)
@@ -2329,54 +2390,13 @@ proto_registrar_is_protocol(int n)
gint
proto_registrar_get_length(int n)
{
- struct header_field_info *hfinfo;
+ header_field_info *hfinfo;
hfinfo = proto_registrar_get_nth(n);
if (!hfinfo)
return -1;
- switch (hfinfo->type) {
- case FT_TEXT_ONLY: /* not filterable */
- case NUM_FIELD_TYPES: /* satisfy picky compilers */
- return -1;
-
- case FT_NONE:
- case FT_BYTES:
- case FT_BOOLEAN:
- case FT_STRING:
- case FT_STRINGZ:
- case FT_UINT_STRING:
- case FT_DOUBLE:
- case FT_ABSOLUTE_TIME:
- case FT_RELATIVE_TIME:
- return 0;
-
- case FT_UINT8:
- case FT_INT8:
- return 1;
-
- case FT_UINT16:
- case FT_INT16:
- return 2;
-
- case FT_UINT24:
- case FT_INT24:
- return 3;
-
- case FT_UINT32:
- case FT_INT32:
- case FT_IPXNET:
- case FT_IPv4:
- return 4;
-
- case FT_ETHER:
- return 6;
-
- case FT_IPv6:
- return 16;
- }
- g_assert_not_reached();
- return -1;
+ return ftype_length(hfinfo->type);
}
@@ -2577,91 +2597,193 @@ proto_registrar_dump(void)
parent_hfinfo = proto_registrar_get_nth(hfinfo->parent);
g_assert(parent_hfinfo);
- enum_name = proto_registrar_ftype_name(hfinfo->type);
+ enum_name = ftype_name(hfinfo->type);
printf("F\t%s\t%s\t%s\t%s\n", hfinfo->name, hfinfo->abbrev,
enum_name,parent_hfinfo->abbrev);
}
}
}
-
-/* Returns a string representing the field type */
-const char*
-proto_registrar_ftype_name(enum ftenum ftype)
+static char*
+hfinfo_numeric_format(header_field_info *hfinfo)
{
- const char *enum_name = NULL;
+ char *format = NULL;
- switch(ftype) {
- case FT_NONE:
- enum_name = "FT_NONE";
+ /* Pick the proper format string */
+ switch(hfinfo->display) {
+ case BASE_DEC:
+ case BASE_NONE:
+ case BASE_OCT: /* I'm lazy */
+ case BASE_BIN: /* I'm lazy */
+ switch(hfinfo->type) {
+ case FT_UINT8:
+ case FT_UINT16:
+ case FT_UINT24:
+ case FT_UINT32:
+ format = "%s == %u";
+ break;
+ case FT_INT8:
+ case FT_INT16:
+ case FT_INT24:
+ case FT_INT32:
+ format = "%s == %d";
+ break;
+ default:
+ g_assert_not_reached();
+ ;
+ }
+ break;
+ case BASE_HEX:
+ switch(hfinfo->type) {
+ case FT_UINT8:
+ format = "%s == 0x%02x";
+ break;
+ case FT_UINT16:
+ format = "%s == 0x%04x";
+ break;
+ case FT_UINT24:
+ format = "%s == 0x%06x";
+ break;
+ case FT_UINT32:
+ format = "%s == 0x%08x";
+ break;
+ default:
+ g_assert_not_reached();
+ ;
+ }
break;
+ default:
+ g_assert_not_reached();
+ ;
+ }
+ return format;
+}
+
+char*
+proto_alloc_dfilter_string(field_info *finfo, guint8 *pd)
+{
+ header_field_info *hfinfo;
+ int abbrev_len;
+ char *buf, *stringified, *format, *ptr;
+ int dfilter_len, i;
+ guint8 *c;
+
+ hfinfo = finfo->hfinfo;
+ g_assert(hfinfo);
+ abbrev_len = strlen(hfinfo->abbrev);
+
+ switch(hfinfo->type) {
+
case FT_BOOLEAN:
- enum_name = "FT_BOOLEAN";
+ dfilter_len = abbrev_len + 2;
+ buf = g_malloc0(dfilter_len);
+ snprintf(buf, dfilter_len, "%s%s", fvalue_get_integer(finfo->value) ? "" : "!",
+ hfinfo->abbrev);
break;
+
case FT_UINT8:
- enum_name = "FT_UINT8";
- break;
case FT_UINT16:
- enum_name = "FT_UINT16";
- break;
case FT_UINT24:
- enum_name = "FT_UINT24";
- break;
case FT_UINT32:
- enum_name = "FT_UINT32";
- break;
case FT_INT8:
- enum_name = "FT_INT8";
- break;
case FT_INT16:
- enum_name = "FT_INT16";
- break;
case FT_INT24:
- enum_name = "FT_INT24";
- break;
case FT_INT32:
- enum_name = "FT_INT32";
- break;
- case FT_DOUBLE:
- enum_name = "FT_DOUBLE";
+ dfilter_len = abbrev_len + 20;
+ buf = g_malloc0(dfilter_len);
+ format = hfinfo_numeric_format(hfinfo);
+ snprintf(buf, dfilter_len, format, hfinfo->abbrev, fvalue_get_integer(finfo->value));
break;
- case FT_ABSOLUTE_TIME:
- enum_name = "FT_ABSOLUTE_TIME";
- break;
- case FT_RELATIVE_TIME:
- enum_name = "FT_RELATIVE_TIME";
+
+ case FT_IPv4:
+ dfilter_len = abbrev_len + 4 + 15 + 1;
+ buf = g_malloc0(dfilter_len);
+ snprintf(buf, dfilter_len, "%s == %s", hfinfo->abbrev,
+ ipv4_addr_str(fvalue_get(finfo->value)));
break;
- case FT_UINT_STRING:
- enum_name = "FT_UINT_STRING";
+
+ case FT_IPXNET:
+ dfilter_len = abbrev_len + 15;
+ buf = g_malloc0(dfilter_len);
+ snprintf(buf, dfilter_len, "%s == 0x%08x", hfinfo->abbrev,
+ fvalue_get_integer(finfo->value));
break;
- case FT_STRING:
- enum_name = "FT_STRING";
+
+ case FT_IPv6:
+ stringified = ip6_to_str((struct e_in6_addr*) fvalue_get(finfo->value));
+ dfilter_len = abbrev_len + 4 + strlen(stringified) + 1;
+ buf = g_malloc0(dfilter_len);
+ snprintf(buf, dfilter_len, "%s == %s", hfinfo->abbrev,
+ stringified);
break;
- case FT_STRINGZ:
- enum_name = "FT_STRINGZ";
+
+ case FT_DOUBLE:
+ dfilter_len = abbrev_len + 30;
+ buf = g_malloc0(dfilter_len);
+ snprintf(buf, dfilter_len, "%s == %f", hfinfo->abbrev,
+ fvalue_get_floating(finfo->value));
break;
+
case FT_ETHER:
- enum_name = "FT_ETHER";
- break;
- case FT_BYTES:
- enum_name = "FT_BYTES";
- break;
- case FT_IPv4:
- enum_name = "FT_IPv4";
- break;
- case FT_IPv6:
- enum_name = "FT_IPv6";
+ dfilter_len = abbrev_len + 22;
+ buf = g_malloc0(dfilter_len);
+ snprintf(buf, dfilter_len, "%s == %s",
+ hfinfo->abbrev,
+ ether_to_str(fvalue_get(finfo->value)));
break;
- case FT_IPXNET:
- enum_name = "FT_IPXNET";
+#if 0
+
+ case FT_ABSOLUTE_TIME:
+ case FT_RELATIVE_TIME:
+ memcpy(&fi->value.time, va_arg(ap, struct timeval*),
+ sizeof(struct timeval));
break;
+
case FT_TEXT_ONLY:
- enum_name = "FT_TEXT_ONLY";
- break;
- case NUM_FIELD_TYPES:
- g_assert_not_reached();
+ ; /* nothing */
break;
+#endif
+
+ case FT_STRING:
+ dfilter_len = abbrev_len +
+ strlen(fvalue_get(finfo->value)) + 7;
+ buf = g_malloc0(dfilter_len);
+ snprintf(buf, dfilter_len, "%s == \"%s\"",
+ hfinfo->abbrev, (char*)fvalue_get(finfo->value));
+ break;
+
+ case FT_BYTES:
+ dfilter_len = finfo->length*3 - 1;
+ dfilter_len += abbrev_len + 7;
+ buf = g_malloc0(dfilter_len);
+ snprintf(buf, dfilter_len, "%s == %s",
+ hfinfo->abbrev,
+ bytes_to_str_punct(fvalue_get(finfo->value), finfo->length,':'));
+ break;
+ default:
+ c = pd + finfo->start;
+ buf = g_malloc0(32 + finfo->length * 3);
+ ptr = buf;
+
+ sprintf(ptr, "frame[%d] == ", finfo->start);
+ ptr = buf+strlen(buf);
+
+ if (finfo->length == 1) {
+ sprintf(ptr, "0x%02x", *c++);
+ }
+ else {
+ for (i=0;i<finfo->length; i++) {
+ if (i == 0 ) {
+ sprintf(ptr, "%02x", *c++);
+ }
+ else {
+ sprintf(ptr, ":%02x", *c++);
+ }
+ ptr = buf+strlen(buf);
+ }
+ }
+ break;
}
- g_assert(enum_name);
- return enum_name;
+
+ return buf;
}
diff --git a/epan/proto.h b/epan/proto.h
index e5abb3fd13..ce6afbf284 100644
--- a/epan/proto.h
+++ b/epan/proto.h
@@ -1,7 +1,7 @@
/* proto.h
* Definitions for protocol display
*
- * $Id: proto.h,v 1.5 2001/02/01 07:34:30 guy Exp $
+ * $Id: proto.h,v 1.6 2001/02/01 20:21:16 gram Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@zing.org>
@@ -43,6 +43,7 @@
#include "ipv4.h"
#include "tvbuff.h"
+#include "ftypes/ftypes.h"
/* needs glib.h */
typedef GNode proto_tree;
@@ -73,34 +74,6 @@ struct value_string;
} \
}
-/* field types */
-enum ftenum {
- FT_NONE, /* used for protocol labels (thus no field type) */
- FT_BOOLEAN, /* TRUE and FALSE come from <glib.h> */
- FT_UINT8,
- FT_UINT16,
- FT_UINT24, /* really a UINT32, but displayed as 3 hex-digits if FD_HEX*/
- FT_UINT32,
- FT_INT8,
- FT_INT16,
- FT_INT24,
- FT_INT32,
- FT_DOUBLE,
- FT_ABSOLUTE_TIME,
- FT_RELATIVE_TIME,
- FT_STRING,
- FT_STRINGZ, /* for use with proto_tree_add_item() */
- FT_UINT_STRING, /* for use with proto_tree_add_item() */
- FT_ETHER,
- FT_BYTES,
- FT_IPv4,
- FT_IPv6,
- FT_IPXNET,
- FT_TEXT_ONLY, /* non-filterable, used when converting ethereal
- from old-style proto_tree to new-style proto_tree */
- NUM_FIELD_TYPES /* last item number plus one */
-};
-
enum {
BASE_NONE,
BASE_DEC,
@@ -109,8 +82,11 @@ enum {
BASE_BIN
};
+typedef struct _header_field_info header_field_info;
+
/* information describing a header field */
-typedef struct header_field_info {
+struct _header_field_info {
+ /* ---------- set by dissector --------- */
char *name;
char *abbrev;
enum ftenum type;
@@ -119,10 +95,12 @@ typedef struct header_field_info {
guint32 bitmask;
char *blurb; /* Brief description of field. */
- int id; /* assigned by registration function, not programmer */
+ /* ---------- set by proto routines --------- */
+ int id; /* Field ID */
int parent; /* parent protocol */
int bitshift; /* bits to shift */
-} header_field_info;
+ header_field_info *same_name; /* Link to next hfinfo with same abbrev*/
+};
@@ -135,22 +113,13 @@ typedef struct hf_register_info {
/* Info stored in each proto_item GNode */
typedef struct field_info {
- struct header_field_info *hfinfo;
+ header_field_info *hfinfo;
gint start;
gint length;
gint tree_type; /* ETT_* */
char *representation; /* for GUI tree */
int visible;
- union {
- guint32 numeric;
- struct timeval time; /* the whole struct, not a pointer */
- gdouble floating;
- gchar *string;
- guint8 *bytes;
- guint8 ether[6];
- ipv4_addr ipv4;
- guint8 ipv6[16];
- } value;
+ fvalue_t *value;
} field_info;
@@ -213,6 +182,18 @@ proto_tree_add_item_hidden(proto_tree *tree, int hfindex, tvbuff_t *tvb,
/* Add a FT_NONE to a proto_tree */
#if __GNUC__ == 2
proto_item *
+proto_tree_add_none_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start,
+ gint length, const char *format, ...)
+ __attribute__((format (printf, 6, 7)));
+#else
+proto_item *
+proto_tree_add_none_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start,
+ gint length, const char *format, ...);
+#endif
+
+/* Add a FT_PROTOCOL to a proto_tree */
+#if __GNUC__ == 2
+proto_item *
proto_tree_add_protocol_format(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start,
gint length, const char *format, ...)
__attribute__((format (printf, 6, 7)));
@@ -487,7 +468,7 @@ char* proto_registrar_get_name(int n);
char* proto_registrar_get_abbrev(int n);
/* get the header field information based upon a field or protocol id */
-struct header_field_info* proto_registrar_get_nth(int hfindex);
+header_field_info* proto_registrar_get_nth(int hfindex);
/* Returns enum ftenum for item # n */
int proto_registrar_get_ftype(int n);
@@ -569,7 +550,10 @@ extern int num_tree_types;
#define g_ptr_array_len(a) ((a)->len)
#endif
-/* Returns a string representing the field type */
-const char* proto_registrar_ftype_name(enum ftenum ftype);
+int
+hfinfo_bitwidth(header_field_info *hfinfo);
+
+char*
+proto_alloc_dfilter_string(field_info *finfo, guint8 *pd);
#endif /* proto.h */