2001-02-01 20:31:21 +00:00
|
|
|
/*
|
2006-05-21 05:12:17 +00:00
|
|
|
* Wireshark - Network traffic analyzer
|
|
|
|
* By Gerald Combs <gerald@wireshark.org>
|
2001-02-01 20:31:21 +00:00
|
|
|
* Copyright 2001 Gerald Combs
|
2002-08-28 20:41:00 +00:00
|
|
|
*
|
2001-02-01 20:31:21 +00:00
|
|
|
* 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.
|
2002-08-28 20:41:00 +00:00
|
|
|
*
|
2001-02-01 20:31:21 +00:00
|
|
|
* 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.
|
2002-08-28 20:41:00 +00:00
|
|
|
*
|
2001-02-01 20:31:21 +00:00
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
2012-06-28 22:56:06 +00:00
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
2001-02-01 20:21:25 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
|
|
|
|
#include <stdio.h>
|
2001-07-13 00:55:58 +00:00
|
|
|
#include <string.h>
|
2001-02-01 20:21:25 +00:00
|
|
|
|
|
|
|
#include "dfilter-int.h"
|
|
|
|
#include "syntax-tree.h"
|
|
|
|
#include "gencode.h"
|
|
|
|
#include "semcheck.h"
|
|
|
|
#include "dfvm.h"
|
2002-01-21 07:37:49 +00:00
|
|
|
#include <epan/epan_dissect.h>
|
2005-08-20 16:19:22 +00:00
|
|
|
#include "dfilter.h"
|
2007-01-18 02:54:56 +00:00
|
|
|
#include "dfilter-macro.h"
|
2001-02-01 20:21:25 +00:00
|
|
|
|
|
|
|
#define DFILTER_TOKEN_ID_OFFSET 1
|
|
|
|
|
|
|
|
/* From scanner.c */
|
2007-01-18 02:54:56 +00:00
|
|
|
void df_scanner_text(const char *text);
|
2001-02-01 20:21:25 +00:00
|
|
|
void df_scanner_cleanup(void);
|
|
|
|
int df_lex(void);
|
|
|
|
|
|
|
|
/* Holds the singular instance of our Lemon parser object */
|
2002-04-08 20:11:31 +00:00
|
|
|
static void* ParserObj = NULL;
|
2001-02-01 20:21:25 +00:00
|
|
|
|
2015-01-18 10:22:19 +00:00
|
|
|
/*
|
|
|
|
* XXX - if we're using a version of Flex that supports reentrant lexical
|
|
|
|
* analyzers, we should put this into the lexical analyzer's state.
|
|
|
|
*/
|
|
|
|
dfwork_t *global_dfw;
|
|
|
|
|
2001-02-01 20:21:25 +00:00
|
|
|
void
|
2015-01-18 10:22:19 +00:00
|
|
|
dfilter_fail(dfwork_t *dfw, const char *format, ...)
|
2001-02-01 20:21:25 +00:00
|
|
|
{
|
|
|
|
va_list args;
|
|
|
|
|
|
|
|
/* If we've already reported one error, don't overwite it */
|
2015-01-18 10:22:19 +00:00
|
|
|
if (dfw->error_message != NULL)
|
2001-02-01 20:21:25 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
va_start(args, format);
|
2015-01-18 10:22:19 +00:00
|
|
|
dfw->error_message = g_strdup_vprintf(format, args);
|
2001-02-01 20:21:25 +00:00
|
|
|
va_end(args);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Initialize the dfilter module */
|
|
|
|
void
|
|
|
|
dfilter_init(void)
|
|
|
|
{
|
|
|
|
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);
|
|
|
|
|
2004-06-15 10:38:14 +00:00
|
|
|
/* Enable parser tracing by defining AM_CFLAGS
|
|
|
|
* so that it contains "-DDFTRACE".
|
|
|
|
*/
|
|
|
|
#ifdef DFTRACE
|
|
|
|
/* Trace parser */
|
|
|
|
DfilterTrace(stdout, "lemon> ");
|
|
|
|
#endif
|
2008-01-31 19:50:38 +00:00
|
|
|
|
2001-02-01 20:21:25 +00:00
|
|
|
/* Initialize the syntax-tree sub-sub-system */
|
|
|
|
sttype_init();
|
2008-01-31 19:50:38 +00:00
|
|
|
|
2007-01-29 04:57:23 +00:00
|
|
|
dfilter_macro_init();
|
2001-02-01 20:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Clean-up the dfilter module */
|
|
|
|
void
|
|
|
|
dfilter_cleanup(void)
|
|
|
|
{
|
|
|
|
/* Free the Lemon Parser object */
|
|
|
|
if (ParserObj) {
|
|
|
|
DfilterFree(ParserObj, g_free);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Clean up the syntax-tree sub-sub-system */
|
|
|
|
sttype_cleanup();
|
|
|
|
}
|
|
|
|
|
|
|
|
static dfilter_t*
|
|
|
|
dfilter_new(void)
|
|
|
|
{
|
|
|
|
dfilter_t *df;
|
|
|
|
|
2009-07-06 15:37:29 +00:00
|
|
|
df = g_new0(dfilter_t, 1);
|
2001-02-01 20:21:25 +00:00
|
|
|
df->insns = NULL;
|
2015-01-18 10:22:19 +00:00
|
|
|
df->deprecated = NULL;
|
2001-02-01 20:21:25 +00:00
|
|
|
|
|
|
|
return df;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Given a GPtrArray of instructions (dfvm_insn_t),
|
|
|
|
* free them. */
|
|
|
|
static void
|
|
|
|
free_insns(GPtrArray *insns)
|
|
|
|
{
|
2001-07-13 00:55:58 +00:00
|
|
|
unsigned int i;
|
2001-02-01 20:21:25 +00:00
|
|
|
dfvm_insn_t *insn;
|
|
|
|
|
|
|
|
for (i = 0; i < insns->len; i++) {
|
2012-06-03 09:26:15 +00:00
|
|
|
insn = (dfvm_insn_t *)g_ptr_array_index(insns, i);
|
2001-02-01 20:21:25 +00:00
|
|
|
dfvm_insn_free(insn);
|
|
|
|
}
|
2007-11-09 05:54:16 +00:00
|
|
|
g_ptr_array_free(insns, TRUE);
|
2001-02-01 20:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
dfilter_free(dfilter_t *df)
|
|
|
|
{
|
2009-10-18 21:30:39 +00:00
|
|
|
guint i;
|
2007-11-28 22:44:37 +00:00
|
|
|
|
|
|
|
if (!df)
|
|
|
|
return;
|
2008-01-31 19:50:38 +00:00
|
|
|
|
2001-02-01 20:21:25 +00:00
|
|
|
if (df->insns) {
|
|
|
|
free_insns(df->insns);
|
|
|
|
}
|
2007-11-28 22:44:37 +00:00
|
|
|
if (df->consts) {
|
|
|
|
free_insns(df->consts);
|
|
|
|
}
|
2001-02-01 20:21:25 +00:00
|
|
|
|
2009-03-13 22:06:48 +00:00
|
|
|
g_free(df->interesting_fields);
|
2008-01-31 19:50:38 +00:00
|
|
|
|
2007-11-28 22:44:37 +00:00
|
|
|
/* clear registers */
|
|
|
|
for (i = 0; i < df->max_registers; i++) {
|
|
|
|
if (df->registers[i]) {
|
|
|
|
g_list_free(df->registers[i]);
|
|
|
|
}
|
|
|
|
}
|
2001-12-18 19:09:08 +00:00
|
|
|
|
2009-09-01 18:16:55 +00:00
|
|
|
if (df->deprecated) {
|
|
|
|
for (i = 0; i < df->deprecated->len; ++i) {
|
2012-06-03 09:26:15 +00:00
|
|
|
gchar *depr = (gchar *)g_ptr_array_index(df->deprecated, i);
|
2009-09-01 18:16:55 +00:00
|
|
|
g_free(depr);
|
|
|
|
}
|
|
|
|
g_ptr_array_free(df->deprecated, TRUE);
|
|
|
|
}
|
|
|
|
|
2001-02-01 20:21:25 +00:00
|
|
|
g_free(df->registers);
|
|
|
|
g_free(df->attempted_load);
|
|
|
|
g_free(df);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static dfwork_t*
|
|
|
|
dfwork_new(void)
|
|
|
|
{
|
|
|
|
dfwork_t *dfw;
|
|
|
|
|
2009-07-06 15:37:29 +00:00
|
|
|
dfw = g_new0(dfwork_t, 1);
|
2007-11-28 22:44:37 +00:00
|
|
|
dfw->first_constant = -1;
|
2001-02-01 20:21:25 +00:00
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2001-12-18 19:09:08 +00:00
|
|
|
if (dfw->interesting_fields) {
|
|
|
|
g_hash_table_destroy(dfw->interesting_fields);
|
|
|
|
}
|
|
|
|
|
2001-02-01 20:21:25 +00:00
|
|
|
if (dfw->insns) {
|
|
|
|
free_insns(dfw->insns);
|
|
|
|
}
|
2007-11-28 22:44:37 +00:00
|
|
|
|
|
|
|
if (dfw->consts) {
|
|
|
|
free_insns(dfw->consts);
|
|
|
|
}
|
2008-01-31 19:50:38 +00:00
|
|
|
|
2015-01-18 10:22:19 +00:00
|
|
|
/*
|
|
|
|
* We don't free the error message string; our caller will return
|
|
|
|
* it to its caller.
|
|
|
|
*/
|
2001-02-01 20:21:25 +00:00
|
|
|
g_free(dfw);
|
|
|
|
}
|
|
|
|
|
|
|
|
gboolean
|
2015-01-18 10:22:19 +00:00
|
|
|
dfilter_compile(const gchar *text, dfilter_t **dfp, gchar **err_msg)
|
2001-02-01 20:21:25 +00:00
|
|
|
{
|
|
|
|
int token;
|
|
|
|
dfilter_t *dfilter;
|
|
|
|
dfwork_t *dfw;
|
2004-06-15 10:38:14 +00:00
|
|
|
gboolean failure = FALSE;
|
2008-01-31 23:10:09 +00:00
|
|
|
const char *depr_test;
|
2008-01-31 19:50:38 +00:00
|
|
|
guint i;
|
2013-08-10 17:49:28 +00:00
|
|
|
/* XXX, GHashTable */
|
2009-08-21 11:31:21 +00:00
|
|
|
GPtrArray *deprecated;
|
|
|
|
|
|
|
|
g_assert(dfp);
|
|
|
|
|
2011-02-17 18:43:38 +00:00
|
|
|
if (!text) {
|
2009-08-21 11:31:21 +00:00
|
|
|
*dfp = NULL;
|
2015-01-18 10:22:19 +00:00
|
|
|
if (err_msg != NULL)
|
|
|
|
*err_msg = g_strdup("BUG: NULL text pointer passed to dfilter_compile()");
|
2009-08-21 11:31:21 +00:00
|
|
|
return FALSE;
|
|
|
|
}
|
2008-01-31 19:50:38 +00:00
|
|
|
|
2015-01-18 10:22:19 +00:00
|
|
|
if ( !( text = dfilter_macro_apply(text, err_msg) ) ) {
|
2007-01-18 02:54:56 +00:00
|
|
|
return FALSE;
|
|
|
|
}
|
2008-01-31 19:50:38 +00:00
|
|
|
|
2001-02-01 20:21:25 +00:00
|
|
|
dfw = dfwork_new();
|
|
|
|
|
2015-01-18 10:22:19 +00:00
|
|
|
/*
|
|
|
|
* XXX - if we're using a version of Flex that supports reentrant lexical
|
|
|
|
* analyzers, we should put this into the lexical analyzer's state.
|
|
|
|
*/
|
|
|
|
global_dfw = dfw;
|
|
|
|
|
2001-02-01 20:21:25 +00:00
|
|
|
df_scanner_text(text);
|
|
|
|
|
2009-08-21 11:31:21 +00:00
|
|
|
deprecated = g_ptr_array_new();
|
|
|
|
|
2001-02-01 20:21:25 +00:00
|
|
|
while (1) {
|
|
|
|
df_lval = stnode_new(STTYPE_UNINITIALIZED, NULL);
|
|
|
|
token = df_lex();
|
|
|
|
|
2004-02-11 22:52:54 +00:00
|
|
|
/* Check for scanner failure */
|
|
|
|
if (token == SCAN_FAILED) {
|
2004-06-15 10:38:14 +00:00
|
|
|
failure = TRUE;
|
|
|
|
break;
|
2004-02-11 22:52:54 +00:00
|
|
|
}
|
|
|
|
|
2001-02-01 20:21:25 +00:00
|
|
|
/* Check for end-of-input */
|
|
|
|
if (token == 0) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2008-01-31 19:50:38 +00:00
|
|
|
/* See if the node is deprecated */
|
|
|
|
depr_test = stnode_deprecated(df_lval);
|
|
|
|
|
|
|
|
if (depr_test) {
|
|
|
|
for (i = 0; i < deprecated->len; i++) {
|
2012-06-03 09:26:15 +00:00
|
|
|
if (g_ascii_strcasecmp(depr_test, (const gchar *)g_ptr_array_index(deprecated, i)) == 0) {
|
2008-01-31 19:50:38 +00:00
|
|
|
/* It's already in our list */
|
|
|
|
depr_test = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (depr_test) {
|
2008-01-31 23:10:09 +00:00
|
|
|
g_ptr_array_add(deprecated, g_strdup(depr_test));
|
2008-01-31 19:50:38 +00:00
|
|
|
}
|
|
|
|
|
2001-02-01 20:21:25 +00:00
|
|
|
/* Give the token to the parser */
|
|
|
|
Dfilter(ParserObj, token, df_lval, dfw);
|
2004-06-15 10:38:14 +00:00
|
|
|
/* We've used the stnode_t, so we don't want to free it */
|
|
|
|
df_lval = NULL;
|
2001-02-01 20:21:25 +00:00
|
|
|
|
|
|
|
if (dfw->syntax_error) {
|
2004-06-15 10:38:14 +00:00
|
|
|
failure = TRUE;
|
2001-02-01 20:21:25 +00:00
|
|
|
break;
|
|
|
|
}
|
2008-01-31 19:50:38 +00:00
|
|
|
|
2004-06-15 10:38:14 +00:00
|
|
|
} /* while (1) */
|
|
|
|
|
|
|
|
/* If we created an stnode_t but didn't use it, free it; the
|
|
|
|
* parser doesn't know about it and won't free it for us. */
|
|
|
|
if (df_lval) {
|
|
|
|
stnode_free(df_lval);
|
|
|
|
df_lval = NULL;
|
2001-02-01 20:21:25 +00:00
|
|
|
}
|
|
|
|
|
2004-06-15 10:38:14 +00:00
|
|
|
/* Tell the parser that we have reached the end of input; that
|
|
|
|
* way, it'll reset its state for the next compile. (We want
|
|
|
|
* to do that even if we got a syntax error, to make sure the
|
2004-06-16 07:33:46 +00:00
|
|
|
* parser state is cleaned up; we don't create a new parser
|
|
|
|
* object when we start a new parse, and don't destroy it when
|
|
|
|
* the parse finishes.) */
|
2004-06-15 10:38:14 +00:00
|
|
|
Dfilter(ParserObj, 0, NULL, dfw);
|
|
|
|
|
2001-02-01 20:21:25 +00:00
|
|
|
/* One last check for syntax error (after EOF) */
|
2004-06-15 10:38:14 +00:00
|
|
|
if (dfw->syntax_error)
|
|
|
|
failure = TRUE;
|
2001-02-01 20:21:25 +00:00
|
|
|
|
2004-06-15 10:38:14 +00:00
|
|
|
/* Reset flex */
|
|
|
|
df_scanner_cleanup();
|
|
|
|
|
|
|
|
if (failure)
|
|
|
|
goto FAILURE;
|
2001-02-01 20:21:25 +00:00
|
|
|
|
|
|
|
/* Success, but was it an empty filter? If so, discard
|
|
|
|
* it and set *dfp to NULL */
|
|
|
|
if (dfw->st_root == NULL) {
|
|
|
|
*dfp = NULL;
|
2008-01-31 23:10:09 +00:00
|
|
|
for (i = 0; i < deprecated->len; ++i) {
|
2012-06-03 09:26:15 +00:00
|
|
|
gchar* depr = (gchar*)g_ptr_array_index(deprecated,i);
|
2008-01-31 23:10:09 +00:00
|
|
|
g_free(depr);
|
|
|
|
}
|
2008-01-31 19:50:38 +00:00
|
|
|
g_ptr_array_free(deprecated, TRUE);
|
2001-02-01 20:21:25 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
|
|
|
|
/* Check semantics and do necessary type conversion*/
|
2013-08-10 17:49:28 +00:00
|
|
|
if (!dfw_semcheck(dfw, deprecated)) {
|
2001-02-01 20:21:25 +00:00
|
|
|
goto FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Create bytecode */
|
|
|
|
dfw_gencode(dfw);
|
2002-08-28 20:41:00 +00:00
|
|
|
|
2001-02-01 20:21:25 +00:00
|
|
|
/* Tuck away the bytecode in the dfilter_t */
|
|
|
|
dfilter = dfilter_new();
|
|
|
|
dfilter->insns = dfw->insns;
|
2007-11-28 22:44:37 +00:00
|
|
|
dfilter->consts = dfw->consts;
|
2001-02-01 20:21:25 +00:00
|
|
|
dfw->insns = NULL;
|
2007-11-28 22:44:37 +00:00
|
|
|
dfw->consts = NULL;
|
2002-10-16 16:32:59 +00:00
|
|
|
dfilter->interesting_fields = dfw_interesting_fields(dfw,
|
|
|
|
&dfilter->num_interesting_fields);
|
2001-02-01 20:21:25 +00:00
|
|
|
|
|
|
|
/* Initialize run-time space */
|
2007-11-28 22:44:37 +00:00
|
|
|
dfilter->num_registers = dfw->first_constant;
|
|
|
|
dfilter->max_registers = dfw->next_register;
|
|
|
|
dfilter->registers = g_new0(GList*, dfilter->max_registers);
|
|
|
|
dfilter->attempted_load = g_new0(gboolean, dfilter->max_registers);
|
|
|
|
|
|
|
|
/* Initialize constants */
|
|
|
|
dfvm_init_const(dfilter);
|
2001-02-01 20:21:25 +00:00
|
|
|
|
2008-01-31 19:50:38 +00:00
|
|
|
/* Add any deprecated items */
|
|
|
|
dfilter->deprecated = deprecated;
|
|
|
|
|
2001-02-01 20:21:25 +00:00
|
|
|
/* And give it to the user. */
|
|
|
|
*dfp = dfilter;
|
|
|
|
}
|
|
|
|
/* SUCCESS */
|
2015-01-18 10:22:19 +00:00
|
|
|
global_dfw = NULL;
|
2001-02-01 20:21:25 +00:00
|
|
|
dfwork_free(dfw);
|
2015-01-17 04:11:49 +00:00
|
|
|
wmem_free(NULL, (char*)text);
|
2001-02-01 20:21:25 +00:00
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
FAILURE:
|
|
|
|
if (dfw) {
|
2015-01-18 10:22:19 +00:00
|
|
|
if (err_msg != NULL)
|
|
|
|
*err_msg = dfw->error_message;
|
|
|
|
else
|
|
|
|
g_free(dfw->error_message);
|
|
|
|
global_dfw = NULL;
|
2001-02-01 20:21:25 +00:00
|
|
|
dfwork_free(dfw);
|
|
|
|
}
|
2008-01-31 23:10:09 +00:00
|
|
|
for (i = 0; i < deprecated->len; ++i) {
|
2012-06-03 09:26:15 +00:00
|
|
|
gchar* depr = (gchar*)g_ptr_array_index(deprecated,i);
|
2008-01-31 23:10:09 +00:00
|
|
|
g_free(depr);
|
|
|
|
}
|
2008-01-31 19:50:38 +00:00
|
|
|
g_ptr_array_free(deprecated, TRUE);
|
2015-01-18 10:22:19 +00:00
|
|
|
if (err_msg != NULL) {
|
|
|
|
/*
|
|
|
|
* Default error message.
|
|
|
|
*
|
|
|
|
* XXX - we should really make sure that this is never the
|
|
|
|
* case for any error.
|
|
|
|
*/
|
|
|
|
if (*err_msg == NULL)
|
|
|
|
*err_msg = g_strdup_printf("Unable to parse filter string \"%s\".", text);
|
|
|
|
}
|
2001-02-01 20:21:25 +00:00
|
|
|
*dfp = NULL;
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
gboolean
|
2002-05-09 23:50:34 +00:00
|
|
|
dfilter_apply(dfilter_t *df, proto_tree *tree)
|
2001-02-01 20:21:25 +00:00
|
|
|
{
|
2002-05-09 23:50:34 +00:00
|
|
|
return dfvm_apply(df, tree);
|
2001-02-01 20:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
gboolean
|
|
|
|
dfilter_apply_edt(dfilter_t *df, epan_dissect_t* edt)
|
|
|
|
{
|
2002-05-09 23:50:34 +00:00
|
|
|
return dfvm_apply(df, edt->tree);
|
2001-02-01 20:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-12-18 19:09:08 +00:00
|
|
|
void
|
2002-09-09 21:04:15 +00:00
|
|
|
dfilter_prime_proto_tree(const dfilter_t *df, proto_tree *tree)
|
2001-12-18 19:09:08 +00:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < df->num_interesting_fields; i++) {
|
2002-05-09 23:50:34 +00:00
|
|
|
proto_tree_prime_hfid(tree, df->interesting_fields[i]);
|
2001-12-18 19:09:08 +00:00
|
|
|
}
|
|
|
|
}
|
2002-08-28 20:41:00 +00:00
|
|
|
|
2008-01-31 19:50:38 +00:00
|
|
|
GPtrArray *
|
|
|
|
dfilter_deprecated_tokens(dfilter_t *df) {
|
|
|
|
if (df->deprecated && df->deprecated->len > 0) {
|
|
|
|
return df->deprecated;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
2001-12-18 19:09:08 +00:00
|
|
|
|
2001-02-01 20:21:25 +00:00
|
|
|
void
|
|
|
|
dfilter_dump(dfilter_t *df)
|
|
|
|
{
|
2008-01-31 19:50:38 +00:00
|
|
|
guint i;
|
2008-06-24 18:22:26 +00:00
|
|
|
const gchar *sep = "";
|
2008-01-31 19:50:38 +00:00
|
|
|
|
2012-02-29 05:58:45 +00:00
|
|
|
dfvm_dump(stdout, df);
|
2008-01-31 19:50:38 +00:00
|
|
|
|
|
|
|
if (df->deprecated && df->deprecated->len) {
|
|
|
|
printf("\nDeprecated tokens: ");
|
|
|
|
for (i = 0; i < df->deprecated->len; i++) {
|
|
|
|
printf("%s\"%s\"", sep, (char *) g_ptr_array_index(df->deprecated, i));
|
|
|
|
sep = ", ";
|
|
|
|
}
|
|
|
|
printf("\n");
|
|
|
|
}
|
2001-02-01 20:21:25 +00:00
|
|
|
}
|