5 * Wireshark - Network traffic analyzer
6 * By Gerald Combs <gerald@wireshark.org>
7 * Copyright 2001 Gerald Combs
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version 2
12 * of the License, or (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
34 #include "dfilter-int.h"
36 #include "dfilter-macro.h"
37 #include <epan/emem.h>
38 #include <epan/uat-int.h>
39 #include <epan/report_err.h>
40 #include <epan/proto.h>
41 #include <wsutil/file_util.h>
49 static uat_t* dfilter_macro_uat = NULL;
50 static dfilter_macro_t* macros = NULL;
51 static guint num_macros;
52 static GHashTable* fvt_cache = NULL;
54 /* #define DUMP_DFILTER_MACRO */
55 #ifdef DUMP_DFILTER_MACRO
56 void dump_dfilter_macro_t(const dfilter_macro_t *m, const char *function, const char *file, int line);
57 #define DUMP_MACRO(m) dump_dfilter_macro_t(m, __func__, __FILE__, __LINE__)
62 static gboolean free_value(gpointer k _U_, gpointer v, gpointer u _U_) {
63 fvt_cache_entry_t* e = (fvt_cache_entry_t*)v;
69 static gboolean fvt_cache_cb(proto_node * node, gpointer data _U_) {
70 field_info* finfo = PNODE_FINFO(node);
73 if (!finfo) return FALSE;
75 if ((e = (fvt_cache_entry_t*)g_hash_table_lookup(fvt_cache,finfo->hfinfo->abbrev))) {
77 } else if (finfo->value.ftype->val_to_string_repr) {
78 switch (finfo->hfinfo->type) {
85 e = g_new(fvt_cache_entry_t,1);
86 e->name = finfo->hfinfo->abbrev,
87 e->repr = fvalue_to_string_repr(&(finfo->value), FTREPR_DFILTER, NULL);
89 g_hash_table_insert(fvt_cache,(void*)finfo->hfinfo->abbrev,e);
94 void dfilter_macro_build_ftv_cache(void* tree_root) {
95 g_hash_table_foreach_remove(fvt_cache,free_value,NULL);
96 proto_tree_traverse_post_order((proto_tree *)tree_root, fvt_cache_cb, NULL);
99 void dfilter_macro_foreach(dfilter_macro_cb_t cb, void* data) {
102 for (i = 0; i < num_macros; i++) {
103 cb(&(macros[i]),data);
108 static void macro_fprint(dfilter_macro_t* m, void* ud) {
111 fprintf(f,"%s\t%s\n",m->name,m->text);
114 void dfilter_macro_save(const gchar* filename, gchar** error) {
115 FILE* f = ws_fopen(filename,"w");
118 *error = ep_strdup_printf("Could not open file: '%s', error: %s\n", filename, g_strerror(errno) );
122 dfilter_macro_foreach(macro_fprint, f);
130 static void macro_dump(dfilter_macro_t* m _U_, void* ud _U_) {
131 gchar** part = m->parts;
132 int* args_pos = m->args_pos;
134 printf("\n->%s\t%s\t%d [%d]\n\t'%s'\n",
135 m->name, m->text, m->argc, m->usable, *(part++));
138 printf("\t$%d '%s'\n",*args_pos,*part);
145 #define macro_dump(a,b)
148 void dfilter_macro_dump(void) {
150 dfilter_macro_foreach(macro_dump, NULL);
154 static gchar* dfilter_macro_resolve(gchar* name, gchar** args, const gchar** error) {
157 dfilter_macro_t* m = NULL;
158 fvt_cache_entry_t* e;
164 for (i = 0; i < num_macros; i++) {
165 dfilter_macro_t* c = &(macros[i]);
166 if ( c->usable && g_str_equal(c->name,name) ) {
174 (e = (fvt_cache_entry_t *)g_hash_table_lookup(fvt_cache,name)) != NULL) {
178 *error = ep_strdup_printf("macro '%s' is unusable", name);
182 *error = ep_strdup_printf("macro '%s' does not exist", name);
190 while(args[argc]) argc++;
193 if (argc != m->argc) {
194 *error = ep_strdup_printf("wrong number of arguments for macro '%s', expecting %d instead of %d",
195 name, m->argc, argc);
199 arg_pos_p = m->args_pos;
202 text = g_string_new(*(parts++));
206 g_string_append_printf(text,"%s%s",
207 args[*(arg_pos_p++)],
212 ret = ep_strdup(text->str);
214 g_string_free(text,TRUE);
220 static gchar* dfilter_macro_apply_recurse(const gchar* text, guint depth, const gchar** error) {
221 enum { OUTSIDE, STARTING, NAME, ARGS } state = OUTSIDE;
223 GString* name = NULL;
225 GPtrArray* args = NULL;
227 const gchar* r = text;
228 gboolean changed = FALSE;
231 *error = "too much nesting in macros";
235 #define FGS(n) if (n) g_string_free(n,TRUE); n = NULL
242 while(args->len) { void* p = g_ptr_array_remove_index_fast(args,0); if (p) g_free(p); } \
243 g_ptr_array_free(args,TRUE); \
249 out = g_string_sized_new(64);
263 g_string_append_c(out,c);
271 args = g_ptr_array_new();
272 arg = g_string_sized_new(32);
273 name = g_string_sized_new(32);
279 g_string_append_c(out,'$');
283 g_string_append_c(out,'$');
284 g_string_append_c(out,c);
293 if ( isalnum((int)c) || c == '_' || c == '-' || c == '.' ) {
294 g_string_append_c(name,c);
295 } else if ( c == ':') {
297 } else if ( c == '}') {
300 g_ptr_array_add(args,NULL);
302 resolved = dfilter_macro_resolve(name->str, (gchar**)args->pdata, error);
303 if (*error) goto on_error;
307 g_string_append(out,resolved);
312 } else if ( c == '\0') {
313 *error = "end of filter in the middle of a macro expression";
316 *error = "invalid char in macro name";
323 *error = "end of filter in the middle of a macro expression";
326 g_ptr_array_add(args,arg->str);
327 g_string_free(arg,FALSE);
329 arg = g_string_sized_new(32);
334 g_string_append_c(arg,c);
337 *error = "end of filter in the middle of a macro expression";
341 g_string_append_c(arg,c);
345 g_ptr_array_add(args,arg->str);
346 g_ptr_array_add(args,NULL);
348 g_string_free(arg,FALSE);
351 resolved = dfilter_macro_resolve(name->str, (gchar**)args->pdata, error);
352 if (*error) goto on_error;
356 g_string_append(out,resolved);
374 gchar* resolved = dfilter_macro_apply_recurse(out->str, depth + 1, error);
375 g_string_free(out,TRUE);
376 return (*error) ? NULL : resolved;
378 gchar* out_str = ep_strdup(out->str);
379 g_string_free(out,TRUE);
386 if (! *error) *error = "unknown error in macro expression";
387 g_string_free(out,TRUE);
392 gchar* dfilter_macro_apply(const gchar* text, const gchar** error) {
393 return dfilter_macro_apply_recurse(text, 0, error);
396 static void macro_update(void* mp, const gchar** error) {
397 dfilter_macro_t* m = (dfilter_macro_t*)mp;
410 for (i = 0; i < num_macros; i++) {
411 if (m == &(macros[i])) continue;
413 if ( g_str_equal(m->name,macros[i].name) ) {
414 *error = ep_strdup_printf("macro '%s' exists already", m->name);
420 /* Invalidate the display filter in case it's in use */
421 if (dfilter_macro_uat && dfilter_macro_uat->post_update_cb)
422 dfilter_macro_uat->post_update_cb();
424 parts = g_ptr_array_new();
425 args_pos = g_array_new(FALSE,FALSE,sizeof(int));
427 m->priv = part = w = g_strdup(m->text);
429 g_ptr_array_add(parts,part);
449 if (c >= '0' && c <= '9') {
463 argc = argc < arg_pos ? arg_pos : argc;
465 g_array_append_val(args_pos,arg_pos);
466 g_ptr_array_add(parts,w);
477 g_ptr_array_add(parts,NULL);
480 m->parts = (gchar**)parts->pdata;
483 m->args_pos = (int*)(void *)args_pos->data;
485 g_ptr_array_free(parts,FALSE);
486 g_array_free(args_pos,FALSE);
499 static void macro_free(void* r) {
500 dfilter_macro_t* m = (dfilter_macro_t*)r;
511 static void* macro_copy(void* dest, const void* orig, size_t len _U_) {
512 dfilter_macro_t* d = (dfilter_macro_t*)dest;
513 const dfilter_macro_t* m = (const dfilter_macro_t*)orig;
517 d->name = g_strdup(m->name);
518 d->text = g_strdup(m->text);
519 d->usable = m->usable;
525 * Copy the contents of m->priv (a "cooked" version
526 * of m->text) into d->priv.
528 * First we clone m->text into d->priv, this gets
529 * us a NUL terminated string of the proper length.
531 * Then we loop copying bytes from m->priv into
532 * d-priv. Since m->priv contains internal ACSII NULs
533 * we use the length of m->text to stop the copy.
536 d->priv = g_strdup(m->text);
538 const gchar* oldText = m->text;
539 const gchar* oldPriv = (const gchar*)m->priv;
540 gchar* newPriv = (gchar*)d->priv;
541 while(oldText && *oldText) {
542 *(newPriv++) = *(oldPriv++);
548 * The contents of the m->parts array contains pointers
549 * into various sections of m->priv. Since it's
550 * an argv style array of ponters, this array is
551 * actually one larger than the number of parts
552 * to hold the final NULL terminator.
554 * The following copy clones the original m->parts
555 * array into d->parts but then fixes-up the pointers
556 * so that they point into the appropriate sections
560 do nparts++; while (m->parts[nparts]);
561 d->parts = (gchar **)g_memdup(m->parts,(nparts+1)*(guint)sizeof(void*));
563 while(m->parts[nparts]) {
565 d->parts[nparts] = d->parts[nparts - 1] + (m->parts[nparts] - m->parts[nparts - 1]);
567 d->parts[nparts] = (gchar *)d->priv;
573 * Clone the contents of m->args_pos into d->args_pos.
576 d->args_pos = (int *)g_memdup(m->args_pos,(--nparts)*(guint)sizeof(int));
584 static gboolean macro_name_chk(void* r _U_, const char* in_name, unsigned name_len, const void* u1 _U_, const void* u2 _U_, const char** error) {
588 *error = "invalid name";
592 for (i=0; i < name_len; i++) {
593 if (!(in_name[i] == '_' || isalnum((guchar)in_name[i]) ) ) {
594 *error = "invalid char in name";
602 UAT_CSTRING_CB_DEF(macro,name,dfilter_macro_t)
603 UAT_CSTRING_CB_DEF(macro,text,dfilter_macro_t)
605 void dfilter_macro_init(void) {
606 static uat_field_t uat_fields[] = {
607 UAT_FLD_CSTRING_OTHER(macro,name,"Name",macro_name_chk,"The name of the macro."),
608 UAT_FLD_CSTRING_ISPRINT(macro,text,"Text","The text this macro resolves to."),
612 dfilter_macro_uat = uat_new("Display Filter Macros",
613 sizeof(dfilter_macro_t),
614 DFILTER_MACRO_FILENAME,
619 "ChDisplayFilterMacrosSection",
623 NULL, /* Note: This is set in macros_init () */
626 fvt_cache = g_hash_table_new(g_str_hash,g_str_equal);
629 void dfilter_macro_get_uat(void** p) {
630 *p = dfilter_macro_uat;
633 #ifdef DUMP_DFILTER_MACRO
635 * The dfilter_macro_t has several characteristics that are
636 * not immediattly obvious. The dump_dfilter_filter_macro_t()
637 * function can be used to help "visualize" the contents of
640 * Some non-obvious components of this struct include:
642 * m->parts is an argv style array of pointers into the
645 * The last pointer of an m->parts array should contain
646 * NULL to indicate the end of the parts pointer array.
648 * m->priv is a "cooked" copy of the m->text string.
649 * Any variable substitution indicators within m->text
650 * ("$1", "$2", ...) will have been replaced with ASCII
651 * NUL characters within m->priv.
653 * The first element of m->parts array (m-parts[0]) will
654 * usually have the same pointer value as m->priv (unless
655 * the dfilter-macro starts off with a variable
656 * substitution indicator (e.g. "$1").
659 void dump_dfilter_macro_t(const dfilter_macro_t *m, const char *function, const char *file, int line)
661 printf("\n<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
664 printf(" dfilter_macro_t * == NULL! (via: %s(): %s:%d)\n", function, file, line);
665 printf("\n>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
668 printf("DUMP of dfilter_macro_t: %p (via: %s(): %s:%d)\n", m, function, file, line);
670 printf(" &dfilter_macro->name == %p\n", &m->name);
671 if(m->name == NULL) {
672 printf(" ->name == NULL\n");
674 printf(" ->name == %p\n", m->name);
675 printf(" ->name == <%s>\n", m->name);
678 printf(" &dfilter_macro->text == %p\n", &m->text);
679 if(m->text == NULL) {
680 printf(" ->text == NULL\n");
682 printf(" ->text == %p\n", m->text);
683 printf(" ->text == <%s>\n", m->text);
686 printf(" &dfilter_macro->usable == %p\n", &m->usable);
687 printf(" ->usable == %u\n", m->usable);
689 printf(" &dfilter_macro->parts == %p\n", &m->parts);
691 if(m->parts == NULL) {
692 printf(" ->parts == NULL\n");
696 while (m->parts[i]) {
697 printf(" ->parts[%d] == %p\n", i, m->parts[i]);
698 printf(" ->parts[%d] == <%s>\n", i, m->parts[i]);
701 printf(" ->parts[%d] == NULL\n", i);
704 printf(" &dfilter_macro->args_pos == %p\n", &m->args_pos);
705 if(m->args_pos == NULL) {
706 printf(" ->args_pos == NULL\n");
708 printf(" ->args_pos == %p\n", m->args_pos);
709 /*printf(" ->args_pos == <%?>\n", m->args_pos);*/
712 printf(" &dfilter_macro->argc == %p\n", &m->argc);
713 printf(" ->argc == %d\n", m->argc);
715 printf(" &dfilter_macro->priv == %p\n", &m->priv);
716 if(m->priv == NULL) {
717 printf(" ->priv == NULL\n");
719 printf(" ->priv == %p\n", m->priv);
720 printf(" ->priv == <%s>\n", (char *)m->priv);
723 printf("\n>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");