2007-01-18 02:54:56 +00:00
|
|
|
/* dfilter-macro.c
|
|
|
|
*
|
2007-01-21 22:32:37 +00:00
|
|
|
* $Id$
|
2007-01-18 02:54:56 +00:00
|
|
|
*
|
|
|
|
* Wireshark - Network traffic analyzer
|
|
|
|
* By Gerald Combs <gerald@wireshark.org>
|
|
|
|
* Copyright 2001 Gerald Combs
|
2007-05-03 16:11:18 +00:00
|
|
|
*
|
2007-01-18 02:54:56 +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.
|
2007-05-03 16:11:18 +00:00
|
|
|
*
|
2007-01-18 02:54:56 +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.
|
2007-05-03 16:11:18 +00:00
|
|
|
*
|
2007-01-18 02:54:56 +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.
|
2007-01-18 02:54:56 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <ctype.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
#include "dfilter-int.h"
|
|
|
|
#include "dfilter.h"
|
|
|
|
#include "dfilter-macro.h"
|
|
|
|
#include <epan/emem.h>
|
2010-08-30 09:31:52 +00:00
|
|
|
#include <epan/uat-int.h>
|
2007-01-29 04:57:23 +00:00
|
|
|
#include <epan/report_err.h>
|
2007-07-30 23:32:47 +00:00
|
|
|
#include <epan/proto.h>
|
2008-05-22 15:46:27 +00:00
|
|
|
#include <wsutil/file_util.h>
|
2007-07-30 23:32:47 +00:00
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
const char* name;
|
|
|
|
gboolean usable;
|
|
|
|
char* repr;
|
|
|
|
} fvt_cache_entry_t;
|
2007-01-18 02:54:56 +00:00
|
|
|
|
2007-01-29 04:57:23 +00:00
|
|
|
static uat_t* dfilter_macro_uat = NULL;
|
|
|
|
static dfilter_macro_t* macros = NULL;
|
|
|
|
static guint num_macros;
|
2007-07-30 23:32:47 +00:00
|
|
|
static GHashTable* fvt_cache = NULL;
|
|
|
|
|
2007-12-29 09:12:29 +00:00
|
|
|
/* #define DUMP_DFILTER_MACRO */
|
|
|
|
#ifdef DUMP_DFILTER_MACRO
|
|
|
|
void dump_dfilter_macro_t(const dfilter_macro_t *m, const char *function, const char *file, int line);
|
|
|
|
#define DUMP_MACRO(m) dump_dfilter_macro_t(m, __func__, __FILE__, __LINE__)
|
|
|
|
#else
|
|
|
|
#define DUMP_MACRO(m)
|
|
|
|
#endif
|
|
|
|
|
2007-07-30 23:32:47 +00:00
|
|
|
static gboolean free_value(gpointer k _U_, gpointer v, gpointer u _U_) {
|
2012-06-02 15:52:42 +00:00
|
|
|
fvt_cache_entry_t* e = (fvt_cache_entry_t*)v;
|
2009-03-13 22:06:48 +00:00
|
|
|
g_free(e->repr);
|
2007-07-30 23:32:47 +00:00
|
|
|
g_free(e);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean fvt_cache_cb(proto_node * node, gpointer data _U_) {
|
2009-08-09 17:57:31 +00:00
|
|
|
field_info* finfo = PNODE_FINFO(node);
|
2007-07-30 23:32:47 +00:00
|
|
|
fvt_cache_entry_t* e;
|
2007-10-16 15:58:25 +00:00
|
|
|
|
2007-07-30 23:32:47 +00:00
|
|
|
if (!finfo) return FALSE;
|
2007-10-16 15:58:25 +00:00
|
|
|
|
2012-06-02 15:52:42 +00:00
|
|
|
if ((e = (fvt_cache_entry_t*)g_hash_table_lookup(fvt_cache,finfo->hfinfo->abbrev))) {
|
2007-07-30 23:32:47 +00:00
|
|
|
e->usable = FALSE;
|
|
|
|
} else if (finfo->value.ftype->val_to_string_repr) {
|
|
|
|
switch (finfo->hfinfo->type) {
|
|
|
|
case FT_NONE:
|
|
|
|
case FT_PROTOCOL:
|
|
|
|
return FALSE;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2012-06-02 15:52:42 +00:00
|
|
|
e = g_new(fvt_cache_entry_t,1);
|
2007-07-30 23:32:47 +00:00
|
|
|
e->name = finfo->hfinfo->abbrev,
|
|
|
|
e->repr = fvalue_to_string_repr(&(finfo->value), FTREPR_DFILTER, NULL);
|
|
|
|
e->usable = TRUE;
|
|
|
|
g_hash_table_insert(fvt_cache,(void*)finfo->hfinfo->abbrev,e);
|
|
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
void dfilter_macro_build_ftv_cache(void* tree_root) {
|
|
|
|
g_hash_table_foreach_remove(fvt_cache,free_value,NULL);
|
2012-06-02 15:52:42 +00:00
|
|
|
proto_tree_traverse_post_order((proto_tree *)tree_root, fvt_cache_cb, NULL);
|
2007-07-30 23:32:47 +00:00
|
|
|
}
|
2007-01-18 02:54:56 +00:00
|
|
|
|
2007-01-29 04:57:23 +00:00
|
|
|
void dfilter_macro_foreach(dfilter_macro_cb_t cb, void* data) {
|
|
|
|
guint i;
|
2007-05-03 16:11:18 +00:00
|
|
|
|
2007-01-29 04:57:23 +00:00
|
|
|
for (i = 0; i < num_macros; i++) {
|
|
|
|
cb(&(macros[i]),data);
|
2007-01-18 02:54:56 +00:00
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void macro_fprint(dfilter_macro_t* m, void* ud) {
|
2012-06-02 15:52:42 +00:00
|
|
|
FILE* f = (FILE*)ud;
|
2007-05-03 16:11:18 +00:00
|
|
|
|
2007-01-18 02:54:56 +00:00
|
|
|
fprintf(f,"%s\t%s\n",m->name,m->text);
|
|
|
|
}
|
|
|
|
|
|
|
|
void dfilter_macro_save(const gchar* filename, gchar** error) {
|
2008-05-22 15:46:27 +00:00
|
|
|
FILE* f = ws_fopen(filename,"w");
|
2007-05-03 16:11:18 +00:00
|
|
|
|
2007-01-18 02:54:56 +00:00
|
|
|
if (!f) {
|
2011-06-28 09:00:11 +00:00
|
|
|
*error = ep_strdup_printf("Could not open file: '%s', error: %s\n", filename, g_strerror(errno) );
|
2007-01-18 02:54:56 +00:00
|
|
|
return;
|
|
|
|
}
|
2007-05-03 16:11:18 +00:00
|
|
|
|
2007-01-18 02:54:56 +00:00
|
|
|
dfilter_macro_foreach(macro_fprint, f);
|
2007-05-03 16:11:18 +00:00
|
|
|
|
2007-01-18 02:54:56 +00:00
|
|
|
fclose(f);
|
2007-05-03 16:11:18 +00:00
|
|
|
|
2007-01-18 02:54:56 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef DUMP_MACROS
|
|
|
|
static void macro_dump(dfilter_macro_t* m _U_, void* ud _U_) {
|
|
|
|
gchar** part = m->parts;
|
|
|
|
int* args_pos = m->args_pos;
|
|
|
|
|
2007-01-29 04:57:23 +00:00
|
|
|
printf("\n->%s\t%s\t%d [%d]\n\t'%s'\n",
|
|
|
|
m->name, m->text, m->argc, m->usable, *(part++));
|
2007-05-03 16:11:18 +00:00
|
|
|
|
2007-01-18 02:54:56 +00:00
|
|
|
while (*part) {
|
|
|
|
printf("\t$%d '%s'\n",*args_pos,*part);
|
2007-05-03 16:11:18 +00:00
|
|
|
|
2007-01-18 02:54:56 +00:00
|
|
|
args_pos++;
|
|
|
|
part++;
|
|
|
|
}
|
|
|
|
}
|
2007-01-29 14:11:44 +00:00
|
|
|
#else
|
|
|
|
#define macro_dump(a,b)
|
2007-01-18 02:54:56 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
void dfilter_macro_dump(void) {
|
|
|
|
#ifdef DUMP_MACROS
|
|
|
|
dfilter_macro_foreach(macro_dump, NULL);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2012-12-26 05:57:06 +00:00
|
|
|
static const gchar* dfilter_macro_resolve(gchar* name, gchar** args, const gchar** error) {
|
2007-01-18 02:54:56 +00:00
|
|
|
GString* text;
|
|
|
|
int argc = 0;
|
2007-01-29 04:57:23 +00:00
|
|
|
dfilter_macro_t* m = NULL;
|
2007-07-30 23:32:47 +00:00
|
|
|
fvt_cache_entry_t* e;
|
2007-01-18 02:54:56 +00:00
|
|
|
int* arg_pos_p;
|
|
|
|
gchar** parts;
|
2012-12-26 05:57:06 +00:00
|
|
|
const gchar* ret;
|
2007-01-29 04:57:23 +00:00
|
|
|
guint i;
|
2007-05-03 16:11:18 +00:00
|
|
|
|
2007-01-29 04:57:23 +00:00
|
|
|
for (i = 0; i < num_macros; i++) {
|
|
|
|
dfilter_macro_t* c = &(macros[i]);
|
|
|
|
if ( c->usable && g_str_equal(c->name,name) ) {
|
|
|
|
m = c;
|
|
|
|
break;
|
|
|
|
}
|
2007-01-18 02:54:56 +00:00
|
|
|
}
|
2007-05-03 16:11:18 +00:00
|
|
|
|
2007-01-18 02:54:56 +00:00
|
|
|
if (!m) {
|
2011-02-17 08:39:41 +00:00
|
|
|
if (fvt_cache &&
|
2012-06-02 15:52:42 +00:00
|
|
|
(e = (fvt_cache_entry_t *)g_hash_table_lookup(fvt_cache,name)) != NULL) {
|
2011-02-17 08:39:41 +00:00
|
|
|
if(e->usable) {
|
2007-07-30 23:32:47 +00:00
|
|
|
return e->repr;
|
|
|
|
} else {
|
|
|
|
*error = ep_strdup_printf("macro '%s' is unusable", name);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
*error = ep_strdup_printf("macro '%s' does not exist", name);
|
|
|
|
return NULL;
|
|
|
|
}
|
2007-01-18 02:54:56 +00:00
|
|
|
}
|
2007-05-03 16:11:18 +00:00
|
|
|
|
2007-12-29 09:12:29 +00:00
|
|
|
DUMP_MACRO(m);
|
|
|
|
|
2007-01-18 02:54:56 +00:00
|
|
|
if (args) {
|
|
|
|
while(args[argc]) argc++;
|
|
|
|
}
|
2007-05-03 16:11:18 +00:00
|
|
|
|
2007-01-18 02:54:56 +00:00
|
|
|
if (argc != m->argc) {
|
|
|
|
*error = ep_strdup_printf("wrong number of arguments for macro '%s', expecting %d instead of %d",
|
|
|
|
name, m->argc, argc);
|
|
|
|
return NULL;
|
|
|
|
}
|
2007-05-03 16:11:18 +00:00
|
|
|
|
2007-01-18 02:54:56 +00:00
|
|
|
arg_pos_p = m->args_pos;
|
|
|
|
parts = m->parts;
|
2007-05-03 16:11:18 +00:00
|
|
|
|
2007-01-18 02:54:56 +00:00
|
|
|
text = g_string_new(*(parts++));
|
2007-05-03 16:11:18 +00:00
|
|
|
|
|
|
|
if (args) {
|
|
|
|
while (*parts) {
|
2008-05-11 18:33:49 +00:00
|
|
|
g_string_append_printf(text,"%s%s",
|
|
|
|
args[*(arg_pos_p++)],
|
|
|
|
*(parts++));
|
2007-05-03 16:11:18 +00:00
|
|
|
}
|
2007-01-18 02:54:56 +00:00
|
|
|
}
|
2007-05-03 16:11:18 +00:00
|
|
|
|
2007-01-18 02:54:56 +00:00
|
|
|
ret = ep_strdup(text->str);
|
2007-05-03 16:11:18 +00:00
|
|
|
|
2007-01-29 04:57:23 +00:00
|
|
|
g_string_free(text,TRUE);
|
2007-05-03 16:11:18 +00:00
|
|
|
|
2007-01-29 04:57:23 +00:00
|
|
|
return ret;
|
2007-01-18 02:54:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-12-26 05:57:06 +00:00
|
|
|
static const gchar* dfilter_macro_apply_recurse(const gchar* text, guint depth, const gchar** error) {
|
2007-01-18 02:54:56 +00:00
|
|
|
enum { OUTSIDE, STARTING, NAME, ARGS } state = OUTSIDE;
|
|
|
|
GString* out;
|
|
|
|
GString* name = NULL;
|
|
|
|
GString* arg = NULL;
|
|
|
|
GPtrArray* args = NULL;
|
|
|
|
gchar c;
|
|
|
|
const gchar* r = text;
|
|
|
|
gboolean changed = FALSE;
|
2007-05-03 16:11:18 +00:00
|
|
|
|
2007-01-18 02:54:56 +00:00
|
|
|
if ( depth > 31) {
|
|
|
|
*error = "too much nesting in macros";
|
|
|
|
return NULL;
|
|
|
|
}
|
2007-05-03 16:11:18 +00:00
|
|
|
|
2007-01-18 02:54:56 +00:00
|
|
|
#define FGS(n) if (n) g_string_free(n,TRUE); n = NULL
|
2007-05-03 16:11:18 +00:00
|
|
|
|
2007-02-03 14:25:02 +00:00
|
|
|
#define FREE_ALL() \
|
|
|
|
do { \
|
|
|
|
FGS(name); \
|
|
|
|
FGS(arg); \
|
|
|
|
if (args) { \
|
|
|
|
while(args->len) { void* p = g_ptr_array_remove_index_fast(args,0); if (p) g_free(p); } \
|
|
|
|
g_ptr_array_free(args,TRUE); \
|
2011-11-15 04:26:38 +00:00
|
|
|
args = NULL; \
|
|
|
|
} \
|
|
|
|
} while(0)
|
2007-05-03 16:11:18 +00:00
|
|
|
|
2011-11-15 04:26:38 +00:00
|
|
|
*error = NULL;
|
|
|
|
out = g_string_sized_new(64);
|
|
|
|
|
|
|
|
while(1) {
|
|
|
|
c = *r++;
|
|
|
|
|
|
|
|
switch(state) {
|
|
|
|
case OUTSIDE: {
|
|
|
|
switch(c) {
|
|
|
|
case '\0': {
|
|
|
|
goto finish;
|
|
|
|
} case '$': {
|
|
|
|
state = STARTING;
|
|
|
|
break;
|
|
|
|
} default: {
|
|
|
|
g_string_append_c(out,c);
|
|
|
|
break;
|
2007-01-18 02:54:56 +00:00
|
|
|
}
|
2011-11-15 04:26:38 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
} case STARTING: {
|
|
|
|
switch (c) {
|
|
|
|
case '{': {
|
|
|
|
args = g_ptr_array_new();
|
|
|
|
arg = g_string_sized_new(32);
|
|
|
|
name = g_string_sized_new(32);
|
2007-05-03 16:11:18 +00:00
|
|
|
|
2011-11-15 04:26:38 +00:00
|
|
|
state = NAME;
|
2007-05-03 16:11:18 +00:00
|
|
|
|
2011-11-15 04:26:38 +00:00
|
|
|
break;
|
|
|
|
} case '\0': {
|
|
|
|
g_string_append_c(out,'$');
|
2007-05-03 16:11:18 +00:00
|
|
|
|
2011-11-15 04:26:38 +00:00
|
|
|
goto finish;
|
|
|
|
} default: {
|
|
|
|
g_string_append_c(out,'$');
|
|
|
|
g_string_append_c(out,c);
|
2007-05-03 16:11:18 +00:00
|
|
|
|
2011-11-15 04:26:38 +00:00
|
|
|
state = OUTSIDE;
|
2007-05-03 16:11:18 +00:00
|
|
|
|
2011-11-15 04:26:38 +00:00
|
|
|
break;
|
2007-01-18 02:54:56 +00:00
|
|
|
}
|
2011-11-15 04:26:38 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
} case NAME: {
|
|
|
|
if ( isalnum((int)c) || c == '_' || c == '-' || c == '.' ) {
|
|
|
|
g_string_append_c(name,c);
|
|
|
|
} else if ( c == ':') {
|
|
|
|
state = ARGS;
|
|
|
|
} else if ( c == '}') {
|
2012-12-26 05:57:06 +00:00
|
|
|
const gchar* resolved;
|
2007-05-03 16:11:18 +00:00
|
|
|
|
2011-11-15 04:26:38 +00:00
|
|
|
g_ptr_array_add(args,NULL);
|
2007-05-03 16:11:18 +00:00
|
|
|
|
2011-11-15 04:26:38 +00:00
|
|
|
resolved = dfilter_macro_resolve(name->str, (gchar**)args->pdata, error);
|
|
|
|
if (*error) goto on_error;
|
2007-05-03 16:11:18 +00:00
|
|
|
|
2011-11-15 04:26:38 +00:00
|
|
|
changed = TRUE;
|
2007-05-03 16:11:18 +00:00
|
|
|
|
2011-11-15 04:26:38 +00:00
|
|
|
g_string_append(out,resolved);
|
2007-05-03 16:11:18 +00:00
|
|
|
|
2011-11-15 04:26:38 +00:00
|
|
|
FREE_ALL();
|
2007-05-03 16:11:18 +00:00
|
|
|
|
2011-11-15 04:26:38 +00:00
|
|
|
state = OUTSIDE;
|
|
|
|
} else if ( c == '\0') {
|
|
|
|
*error = "end of filter in the middle of a macro expression";
|
|
|
|
goto on_error;
|
|
|
|
} else {
|
|
|
|
*error = "invalid char in macro name";
|
|
|
|
goto on_error;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
} case ARGS: {
|
|
|
|
switch(c) {
|
|
|
|
case '\0': {
|
2007-01-18 02:54:56 +00:00
|
|
|
*error = "end of filter in the middle of a macro expression";
|
2007-05-03 16:11:18 +00:00
|
|
|
goto on_error;
|
2011-11-15 04:26:38 +00:00
|
|
|
} case ';': {
|
|
|
|
g_ptr_array_add(args,arg->str);
|
|
|
|
g_string_free(arg,FALSE);
|
|
|
|
|
|
|
|
arg = g_string_sized_new(32);
|
|
|
|
break;
|
|
|
|
} case '\\': {
|
|
|
|
c = *r++;
|
|
|
|
if (c) {
|
2007-01-18 02:54:56 +00:00
|
|
|
g_string_append_c(arg,c);
|
|
|
|
break;
|
2011-11-15 04:26:38 +00:00
|
|
|
} else {
|
|
|
|
*error = "end of filter in the middle of a macro expression";
|
|
|
|
goto on_error;
|
|
|
|
}
|
|
|
|
} default: {
|
|
|
|
g_string_append_c(arg,c);
|
|
|
|
break;
|
|
|
|
} case '}': {
|
2012-12-26 05:57:06 +00:00
|
|
|
const gchar* resolved;
|
2011-11-15 04:26:38 +00:00
|
|
|
g_ptr_array_add(args,arg->str);
|
|
|
|
g_ptr_array_add(args,NULL);
|
2007-01-18 02:54:56 +00:00
|
|
|
|
2011-11-15 04:26:38 +00:00
|
|
|
g_string_free(arg,FALSE);
|
|
|
|
arg = NULL;
|
2007-05-03 16:11:18 +00:00
|
|
|
|
2011-11-15 04:26:38 +00:00
|
|
|
resolved = dfilter_macro_resolve(name->str, (gchar**)args->pdata, error);
|
|
|
|
if (*error) goto on_error;
|
2007-05-03 16:11:18 +00:00
|
|
|
|
2011-11-15 04:26:38 +00:00
|
|
|
changed = TRUE;
|
2007-05-03 16:11:18 +00:00
|
|
|
|
2011-11-15 04:26:38 +00:00
|
|
|
g_string_append(out,resolved);
|
2007-05-03 16:11:18 +00:00
|
|
|
|
2011-11-15 04:26:38 +00:00
|
|
|
FREE_ALL();
|
2007-05-03 16:11:18 +00:00
|
|
|
|
2011-11-15 04:26:38 +00:00
|
|
|
state = OUTSIDE;
|
|
|
|
break;
|
2007-01-18 02:54:56 +00:00
|
|
|
}
|
|
|
|
}
|
2011-11-15 04:26:38 +00:00
|
|
|
break;
|
2007-01-18 02:54:56 +00:00
|
|
|
}
|
|
|
|
}
|
2011-11-15 04:26:38 +00:00
|
|
|
}
|
2007-05-03 16:11:18 +00:00
|
|
|
|
2007-01-18 02:54:56 +00:00
|
|
|
finish:
|
2011-11-15 04:26:38 +00:00
|
|
|
{
|
|
|
|
FREE_ALL();
|
2007-05-03 16:11:18 +00:00
|
|
|
|
2011-11-15 04:26:38 +00:00
|
|
|
if (changed) {
|
2012-12-26 05:57:06 +00:00
|
|
|
const gchar* resolved = dfilter_macro_apply_recurse(out->str, depth + 1, error);
|
2007-01-18 02:54:56 +00:00
|
|
|
g_string_free(out,TRUE);
|
2011-11-15 04:26:38 +00:00
|
|
|
return (*error) ? NULL : resolved;
|
|
|
|
} else {
|
2012-12-26 05:57:06 +00:00
|
|
|
const gchar* out_str = ep_strdup(out->str);
|
2011-11-15 04:26:38 +00:00
|
|
|
g_string_free(out,TRUE);
|
|
|
|
return out_str;
|
2007-01-18 02:54:56 +00:00
|
|
|
}
|
2011-11-15 04:26:38 +00:00
|
|
|
}
|
|
|
|
on_error:
|
|
|
|
{
|
|
|
|
FREE_ALL();
|
|
|
|
if (! *error) *error = "unknown error in macro expression";
|
|
|
|
g_string_free(out,TRUE);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-12-26 05:57:06 +00:00
|
|
|
const gchar* dfilter_macro_apply(const gchar* text, const gchar** error) {
|
2011-11-15 04:26:38 +00:00
|
|
|
return dfilter_macro_apply_recurse(text, 0, error);
|
2007-01-18 02:54:56 +00:00
|
|
|
}
|
2007-01-29 04:57:23 +00:00
|
|
|
|
2007-04-23 10:59:26 +00:00
|
|
|
static void macro_update(void* mp, const gchar** error) {
|
2012-06-02 15:52:42 +00:00
|
|
|
dfilter_macro_t* m = (dfilter_macro_t*)mp;
|
2007-01-29 04:57:23 +00:00
|
|
|
GPtrArray* parts;
|
|
|
|
GArray* args_pos;
|
|
|
|
const gchar* r;
|
|
|
|
gchar* w;
|
|
|
|
gchar* part;
|
|
|
|
int argc = 0;
|
|
|
|
guint i;
|
2007-05-03 16:11:18 +00:00
|
|
|
|
2007-12-29 09:12:29 +00:00
|
|
|
DUMP_MACRO(m);
|
|
|
|
|
2007-01-29 04:57:23 +00:00
|
|
|
*error = NULL;
|
2007-05-03 16:11:18 +00:00
|
|
|
|
2007-01-29 04:57:23 +00:00
|
|
|
for (i = 0; i < num_macros; i++) {
|
|
|
|
if (m == &(macros[i])) continue;
|
2007-05-03 16:11:18 +00:00
|
|
|
|
2007-01-29 04:57:23 +00:00
|
|
|
if ( g_str_equal(m->name,macros[i].name) ) {
|
|
|
|
*error = ep_strdup_printf("macro '%s' exists already", m->name);
|
|
|
|
m->usable = FALSE;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2007-05-03 16:11:18 +00:00
|
|
|
|
2010-08-30 08:47:26 +00:00
|
|
|
/* Invalidate the display filter in case it's in use */
|
2010-08-30 09:31:52 +00:00
|
|
|
if (dfilter_macro_uat && dfilter_macro_uat->post_update_cb)
|
|
|
|
dfilter_macro_uat->post_update_cb();
|
2010-08-30 08:47:26 +00:00
|
|
|
|
2007-01-29 04:57:23 +00:00
|
|
|
parts = g_ptr_array_new();
|
|
|
|
args_pos = g_array_new(FALSE,FALSE,sizeof(int));
|
|
|
|
|
|
|
|
m->priv = part = w = g_strdup(m->text);
|
|
|
|
r = m->text;
|
|
|
|
g_ptr_array_add(parts,part);
|
2007-05-03 16:11:18 +00:00
|
|
|
|
|
|
|
while (r && *r) {
|
|
|
|
|
|
|
|
switch (*r) {
|
2007-01-29 04:57:23 +00:00
|
|
|
default:
|
|
|
|
*(w++) = *(r++);
|
|
|
|
break;
|
|
|
|
case '\0':
|
2011-11-15 04:26:38 +00:00
|
|
|
*w = *r;
|
2007-01-29 04:57:23 +00:00
|
|
|
goto done;
|
|
|
|
case '\\':
|
|
|
|
*(w++) = *(++r);
|
|
|
|
r++;
|
|
|
|
break;
|
|
|
|
case '$': {
|
|
|
|
int cnt = 0;
|
|
|
|
int arg_pos = 0;
|
|
|
|
do {
|
|
|
|
char c = *(r+1);
|
|
|
|
if (c >= '0' && c <= '9') {
|
|
|
|
cnt++;
|
|
|
|
r++;
|
2007-05-16 17:35:07 +00:00
|
|
|
*(w++) = '\0';
|
2007-01-29 04:57:23 +00:00
|
|
|
arg_pos *= 10;
|
|
|
|
arg_pos += c - '0';
|
|
|
|
} else {
|
|
|
|
break;
|
|
|
|
}
|
2007-05-03 16:11:18 +00:00
|
|
|
} while(*r);
|
|
|
|
|
2007-01-29 04:57:23 +00:00
|
|
|
if (cnt) {
|
|
|
|
*(w++) = '\0';
|
|
|
|
r++;
|
|
|
|
argc = argc < arg_pos ? arg_pos : argc;
|
|
|
|
arg_pos--;
|
|
|
|
g_array_append_val(args_pos,arg_pos);
|
|
|
|
g_ptr_array_add(parts,w);
|
|
|
|
} else {
|
|
|
|
*(w++) = *(r++);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2007-05-03 16:11:18 +00:00
|
|
|
|
|
|
|
}
|
2007-01-29 04:57:23 +00:00
|
|
|
|
|
|
|
done:
|
|
|
|
g_ptr_array_add(parts,NULL);
|
|
|
|
|
2009-03-13 22:06:48 +00:00
|
|
|
g_free(m->parts);
|
2007-01-29 04:57:23 +00:00
|
|
|
m->parts = (gchar**)parts->pdata;
|
2007-05-03 16:11:18 +00:00
|
|
|
|
2009-03-13 22:06:48 +00:00
|
|
|
g_free(m->args_pos);
|
2007-04-24 06:43:01 +00:00
|
|
|
m->args_pos = (int*)(void *)args_pos->data;
|
2007-01-29 04:57:23 +00:00
|
|
|
|
|
|
|
g_ptr_array_free(parts,FALSE);
|
|
|
|
g_array_free(args_pos,FALSE);
|
2007-05-03 16:11:18 +00:00
|
|
|
|
2007-01-29 04:57:23 +00:00
|
|
|
m->argc = argc;
|
2007-05-03 16:11:18 +00:00
|
|
|
|
2007-01-29 04:57:23 +00:00
|
|
|
m->usable = TRUE;
|
2007-05-03 16:11:18 +00:00
|
|
|
|
2007-01-29 14:11:44 +00:00
|
|
|
macro_dump(m,NULL);
|
2007-05-03 16:11:18 +00:00
|
|
|
|
2007-12-29 09:12:29 +00:00
|
|
|
DUMP_MACRO(m);
|
|
|
|
|
2007-01-29 04:57:23 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void macro_free(void* r) {
|
2012-06-02 15:52:42 +00:00
|
|
|
dfilter_macro_t* m = (dfilter_macro_t*)r;
|
2007-05-03 16:11:18 +00:00
|
|
|
|
2007-12-29 09:12:29 +00:00
|
|
|
DUMP_MACRO(r);
|
|
|
|
|
2007-01-29 04:57:23 +00:00
|
|
|
g_free(m->name);
|
|
|
|
g_free(m->text);
|
|
|
|
g_free(m->priv);
|
|
|
|
g_free(m->parts);
|
|
|
|
g_free(m->args_pos);
|
|
|
|
}
|
|
|
|
|
2010-10-29 21:11:33 +00:00
|
|
|
static void* macro_copy(void* dest, const void* orig, size_t len _U_) {
|
2012-06-02 15:52:42 +00:00
|
|
|
dfilter_macro_t* d = (dfilter_macro_t*)dest;
|
2012-06-03 09:26:15 +00:00
|
|
|
const dfilter_macro_t* m = (const dfilter_macro_t*)orig;
|
2007-12-29 09:12:29 +00:00
|
|
|
|
|
|
|
DUMP_MACRO(m);
|
2007-01-29 04:57:23 +00:00
|
|
|
|
|
|
|
d->name = g_strdup(m->name);
|
|
|
|
d->text = g_strdup(m->text);
|
|
|
|
d->usable = m->usable;
|
|
|
|
|
|
|
|
if (m->parts) {
|
2007-12-29 09:12:29 +00:00
|
|
|
guint nparts = 0;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Copy the contents of m->priv (a "cooked" version
|
|
|
|
* of m->text) into d->priv.
|
2008-05-22 15:46:27 +00:00
|
|
|
*
|
2007-12-29 09:12:29 +00:00
|
|
|
* First we clone m->text into d->priv, this gets
|
|
|
|
* us a NUL terminated string of the proper length.
|
|
|
|
*
|
2008-05-22 15:46:27 +00:00
|
|
|
* Then we loop copying bytes from m->priv into
|
|
|
|
* d-priv. Since m->priv contains internal ACSII NULs
|
2007-12-29 09:12:29 +00:00
|
|
|
* we use the length of m->text to stop the copy.
|
|
|
|
*/
|
|
|
|
|
|
|
|
d->priv = g_strdup(m->text);
|
|
|
|
{
|
|
|
|
const gchar* oldText = m->text;
|
2012-06-02 15:52:42 +00:00
|
|
|
const gchar* oldPriv = (const gchar*)m->priv;
|
|
|
|
gchar* newPriv = (gchar*)d->priv;
|
2007-12-29 09:12:29 +00:00
|
|
|
while(oldText && *oldText) {
|
|
|
|
*(newPriv++) = *(oldPriv++);
|
2008-05-22 15:46:27 +00:00
|
|
|
oldText++;
|
2007-12-29 09:12:29 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The contents of the m->parts array contains pointers
|
|
|
|
* into various sections of m->priv. Since it's
|
|
|
|
* an argv style array of ponters, this array is
|
|
|
|
* actually one larger than the number of parts
|
|
|
|
* to hold the final NULL terminator.
|
|
|
|
*
|
|
|
|
* The following copy clones the original m->parts
|
2008-05-22 15:46:27 +00:00
|
|
|
* array into d->parts but then fixes-up the pointers
|
|
|
|
* so that they point into the appropriate sections
|
2007-12-29 09:12:29 +00:00
|
|
|
* of the d->priv.
|
|
|
|
*/
|
|
|
|
|
2007-05-03 16:11:18 +00:00
|
|
|
do nparts++; while (m->parts[nparts]);
|
2012-06-02 15:52:42 +00:00
|
|
|
d->parts = (gchar **)g_memdup(m->parts,(nparts+1)*(guint)sizeof(void*));
|
2007-12-29 09:12:29 +00:00
|
|
|
nparts = 0;
|
|
|
|
while(m->parts[nparts]) {
|
|
|
|
if(nparts) {
|
|
|
|
d->parts[nparts] = d->parts[nparts - 1] + (m->parts[nparts] - m->parts[nparts - 1]);
|
|
|
|
} else {
|
2012-06-02 15:52:42 +00:00
|
|
|
d->parts[nparts] = (gchar *)d->priv;
|
2007-12-29 09:12:29 +00:00
|
|
|
}
|
|
|
|
nparts++;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Clone the contents of m->args_pos into d->args_pos.
|
|
|
|
*/
|
|
|
|
|
2012-06-02 15:52:42 +00:00
|
|
|
d->args_pos = (int *)g_memdup(m->args_pos,(--nparts)*(guint)sizeof(int));
|
2007-01-29 04:57:23 +00:00
|
|
|
}
|
2007-05-03 16:11:18 +00:00
|
|
|
|
2007-12-29 09:12:29 +00:00
|
|
|
DUMP_MACRO(d);
|
2007-05-03 16:11:18 +00:00
|
|
|
|
2007-01-29 04:57:23 +00:00
|
|
|
return d;
|
|
|
|
}
|
|
|
|
|
2013-01-04 05:22:43 +00:00
|
|
|
static gboolean macro_name_chk(void* r _U_, const char* in_name, guint name_len, const void* u1 _U_, const void* u2 _U_, const char** error) {
|
2007-01-29 04:57:23 +00:00
|
|
|
guint i;
|
2007-05-03 16:11:18 +00:00
|
|
|
|
2007-09-02 12:37:24 +00:00
|
|
|
if (name_len == 0) {
|
|
|
|
*error = "invalid name";
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2007-01-29 04:57:23 +00:00
|
|
|
for (i=0; i < name_len; i++) {
|
2007-07-14 00:37:01 +00:00
|
|
|
if (!(in_name[i] == '_' || isalnum((guchar)in_name[i]) ) ) {
|
2007-01-29 04:57:23 +00:00
|
|
|
*error = "invalid char in name";
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
}
|
2007-05-03 16:11:18 +00:00
|
|
|
|
2007-09-02 12:37:24 +00:00
|
|
|
return TRUE;
|
2007-01-29 04:57:23 +00:00
|
|
|
}
|
|
|
|
|
2007-02-03 14:25:02 +00:00
|
|
|
UAT_CSTRING_CB_DEF(macro,name,dfilter_macro_t)
|
|
|
|
UAT_CSTRING_CB_DEF(macro,text,dfilter_macro_t)
|
2007-01-29 04:57:23 +00:00
|
|
|
|
|
|
|
void dfilter_macro_init(void) {
|
2007-02-03 14:25:02 +00:00
|
|
|
static uat_field_t uat_fields[] = {
|
2009-02-16 04:10:06 +00:00
|
|
|
UAT_FLD_CSTRING_OTHER(macro,name,"Name",macro_name_chk,"The name of the macro."),
|
2013-06-19 17:11:55 +00:00
|
|
|
/* N.B. it would be nice if there was a field type for display filters (with
|
|
|
|
auto-completion & colouring), but this wouldn't work here as the filter string
|
|
|
|
will contain $1, etc... */
|
2009-02-16 04:10:06 +00:00
|
|
|
UAT_FLD_CSTRING_ISPRINT(macro,text,"Text","The text this macro resolves to."),
|
2007-02-03 14:25:02 +00:00
|
|
|
UAT_END_FIELDS
|
|
|
|
};
|
2007-05-03 16:11:18 +00:00
|
|
|
|
2007-02-12 19:57:41 +00:00
|
|
|
dfilter_macro_uat = uat_new("Display Filter Macros",
|
2007-04-03 21:17:13 +00:00
|
|
|
sizeof(dfilter_macro_t),
|
|
|
|
DFILTER_MACRO_FILENAME,
|
2008-03-06 22:13:24 +00:00
|
|
|
TRUE,
|
2013-03-17 16:48:47 +00:00
|
|
|
(void**) ¯os,
|
2007-04-03 21:17:13 +00:00
|
|
|
&num_macros,
|
UATs could be put into "categories". The categories were defined only
implicitly by the #define name and string they were defined to; not all
UATs neatly fit into any of the categories, so some of them were put
into categories that weren't obviously correct for them, and one - the
display filter macro UAT - wasn't put into any category at all (which
caused crashes when editing them, as the GUI code that handled UAT
changes from a dialog assumed the category field was non-null).
The category was, in practice, used only to decide, in the
aforementioned GUI code, whether the packet summary pane needed to be
updated or not. It also offered no option of "don't update the packet
summary pane *and* don't redissect anything", which is what would be
appropriate for the display filter macro UAT.
Replace the category with a set of fields indicating what the UAT
affects; we currently offer "dissection", which applies to most UATs
(any UAT in libwireshark presumably affects dissection at a minimum) and
"the set of named fields that exist". Changing any UAT that affects
dissection requires a redissection; changing any UAT that affects the
set of named fields that exist requires a redissection *and* rebuilding
the packet summary pane.
Perhaps we also need "filtering", so that if you change a display filter
macro, we re-filter, in case the display is currently filtered with a
display filter that uses a macro that changed.
svn path=/trunk/; revision=43603
2012-07-08 01:00:46 +00:00
|
|
|
0, /* doesn't affect anything that requires a GUI update */
|
2007-04-03 21:17:13 +00:00
|
|
|
"ChDisplayFilterMacrosSection",
|
|
|
|
macro_copy,
|
|
|
|
macro_update,
|
|
|
|
macro_free,
|
2010-08-30 08:47:26 +00:00
|
|
|
NULL, /* Note: This is set in macros_init () */
|
2007-04-03 21:17:13 +00:00
|
|
|
uat_fields);
|
2007-07-30 23:32:47 +00:00
|
|
|
|
|
|
|
fvt_cache = g_hash_table_new(g_str_hash,g_str_equal);
|
2007-01-29 04:57:23 +00:00
|
|
|
}
|
2007-01-29 10:23:38 +00:00
|
|
|
|
|
|
|
void dfilter_macro_get_uat(void** p) {
|
|
|
|
*p = dfilter_macro_uat;
|
|
|
|
}
|
2007-07-30 23:32:47 +00:00
|
|
|
|
2007-12-29 09:12:29 +00:00
|
|
|
#ifdef DUMP_DFILTER_MACRO
|
|
|
|
/*
|
|
|
|
* The dfilter_macro_t has several characteristics that are
|
2013-06-19 17:11:55 +00:00
|
|
|
* not immediately obvious. The dump_dfilter_filter_macro_t()
|
2008-05-22 15:46:27 +00:00
|
|
|
* function can be used to help "visualize" the contents of
|
2007-12-29 09:12:29 +00:00
|
|
|
* a dfilter_macro_t.
|
|
|
|
*
|
|
|
|
* Some non-obvious components of this struct include:
|
|
|
|
*
|
|
|
|
* m->parts is an argv style array of pointers into the
|
2008-05-22 15:46:27 +00:00
|
|
|
* m->priv string.
|
2007-12-29 09:12:29 +00:00
|
|
|
*
|
|
|
|
* The last pointer of an m->parts array should contain
|
|
|
|
* NULL to indicate the end of the parts pointer array.
|
|
|
|
*
|
|
|
|
* m->priv is a "cooked" copy of the m->text string.
|
2008-05-22 15:46:27 +00:00
|
|
|
* Any variable substitution indicators within m->text
|
|
|
|
* ("$1", "$2", ...) will have been replaced with ASCII
|
2007-12-29 09:12:29 +00:00
|
|
|
* NUL characters within m->priv.
|
|
|
|
*
|
2008-05-22 15:46:27 +00:00
|
|
|
* The first element of m->parts array (m-parts[0]) will
|
|
|
|
* usually have the same pointer value as m->priv (unless
|
|
|
|
* the dfilter-macro starts off with a variable
|
2007-12-29 09:12:29 +00:00
|
|
|
* substitution indicator (e.g. "$1").
|
|
|
|
*/
|
|
|
|
|
|
|
|
void dump_dfilter_macro_t(const dfilter_macro_t *m, const char *function, const char *file, int line)
|
|
|
|
{
|
|
|
|
printf("\n<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
|
|
|
|
|
|
|
|
if(m == NULL) {
|
|
|
|
printf(" dfilter_macro_t * == NULL! (via: %s(): %s:%d)\n", function, file, line);
|
|
|
|
printf("\n>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
printf("DUMP of dfilter_macro_t: %p (via: %s(): %s:%d)\n", m, function, file, line);
|
|
|
|
|
|
|
|
printf(" &dfilter_macro->name == %p\n", &m->name);
|
|
|
|
if(m->name == NULL) {
|
|
|
|
printf(" ->name == NULL\n");
|
|
|
|
} else {
|
|
|
|
printf(" ->name == %p\n", m->name);
|
|
|
|
printf(" ->name == <%s>\n", m->name);
|
|
|
|
}
|
|
|
|
|
|
|
|
printf(" &dfilter_macro->text == %p\n", &m->text);
|
|
|
|
if(m->text == NULL) {
|
|
|
|
printf(" ->text == NULL\n");
|
|
|
|
} else {
|
|
|
|
printf(" ->text == %p\n", m->text);
|
|
|
|
printf(" ->text == <%s>\n", m->text);
|
|
|
|
}
|
|
|
|
|
|
|
|
printf(" &dfilter_macro->usable == %p\n", &m->usable);
|
|
|
|
printf(" ->usable == %u\n", m->usable);
|
2007-07-30 23:32:47 +00:00
|
|
|
|
2007-12-29 09:12:29 +00:00
|
|
|
printf(" &dfilter_macro->parts == %p\n", &m->parts);
|
2007-07-30 23:32:47 +00:00
|
|
|
|
2007-12-29 09:12:29 +00:00
|
|
|
if(m->parts == NULL) {
|
|
|
|
printf(" ->parts == NULL\n");
|
|
|
|
} else {
|
|
|
|
int i = 0;
|
|
|
|
|
|
|
|
while (m->parts[i]) {
|
|
|
|
printf(" ->parts[%d] == %p\n", i, m->parts[i]);
|
|
|
|
printf(" ->parts[%d] == <%s>\n", i, m->parts[i]);
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
printf(" ->parts[%d] == NULL\n", i);
|
|
|
|
}
|
|
|
|
|
|
|
|
printf(" &dfilter_macro->args_pos == %p\n", &m->args_pos);
|
|
|
|
if(m->args_pos == NULL) {
|
|
|
|
printf(" ->args_pos == NULL\n");
|
|
|
|
} else {
|
|
|
|
printf(" ->args_pos == %p\n", m->args_pos);
|
|
|
|
/*printf(" ->args_pos == <%?>\n", m->args_pos);*/
|
|
|
|
}
|
|
|
|
|
|
|
|
printf(" &dfilter_macro->argc == %p\n", &m->argc);
|
|
|
|
printf(" ->argc == %d\n", m->argc);
|
|
|
|
|
|
|
|
printf(" &dfilter_macro->priv == %p\n", &m->priv);
|
|
|
|
if(m->priv == NULL) {
|
|
|
|
printf(" ->priv == NULL\n");
|
|
|
|
} else {
|
|
|
|
printf(" ->priv == %p\n", m->priv);
|
|
|
|
printf(" ->priv == <%s>\n", (char *)m->priv);
|
|
|
|
}
|
|
|
|
|
|
|
|
printf("\n>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
|
|
|
|
}
|
|
|
|
#endif
|
2007-10-16 15:58:25 +00:00
|
|
|
|