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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
34 #include "dfilter-int.h"
36 #include "dfilter-macro.h"
37 #include <epan/emem.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 = v;
64 if (e->repr) g_free(e->repr);
69 static gboolean fvt_cache_cb(proto_node * node, gpointer data _U_) {
70 field_info* finfo = node->finfo;
73 if (!finfo) return FALSE;
75 if ((e = 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_malloc(sizeof(fvt_cache_entry_t));
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(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, 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) ) {
173 if (fvt_cache && (e = g_hash_table_lookup(fvt_cache,name) )) {
177 *error = ep_strdup_printf("macro '%s' is unusable", name);
181 *error = ep_strdup_printf("macro '%s' does not exist", name);
189 while(args[argc]) argc++;
192 if (argc != m->argc) {
193 *error = ep_strdup_printf("wrong number of arguments for macro '%s', expecting %d instead of %d",
194 name, m->argc, argc);
198 arg_pos_p = m->args_pos;
201 text = g_string_new(*(parts++));
205 g_string_append_printf(text,"%s%s",
206 args[*(arg_pos_p++)],
211 ret = ep_strdup(text->str);
213 g_string_free(text,TRUE);
219 gchar* dfilter_macro_apply(const gchar* text, guint depth, const gchar** error) {
220 enum { OUTSIDE, STARTING, NAME, ARGS } state = OUTSIDE;
222 GString* name = NULL;
224 GPtrArray* args = NULL;
226 const gchar* r = text;
227 gboolean changed = FALSE;
230 *error = "too much nesting in macros";
234 #define FGS(n) if (n) g_string_free(n,TRUE); n = NULL
241 while(args->len) { void* p = g_ptr_array_remove_index_fast(args,0); if (p) g_free(p); } \
242 g_ptr_array_free(args,TRUE); \
243 args = NULL; } } while(0)
246 out = g_string_sized_new(64);
260 g_string_append_c(out,c);
268 args = g_ptr_array_new();
269 arg = g_string_sized_new(32);
270 name = g_string_sized_new(32);
276 g_string_append_c(out,'$');
280 g_string_append_c(out,'$');
281 g_string_append_c(out,c);
290 if ( isalnum((int)c) || c == '_' || c == '-' || c == '.' ) {
291 g_string_append_c(name,c);
292 } else if ( c == ':') {
294 } else if ( c == '}') {
297 g_ptr_array_add(args,NULL);
299 resolved = dfilter_macro_resolve(name->str, (gchar**)args->pdata, error);
300 if (*error) goto on_error;
304 g_string_append(out,resolved);
309 } else if ( c == '\0') {
310 *error = "end of filter in the middle of a macro expression";
313 *error = "invalid char in macro name";
320 *error = "end of filter in the middle of a macro expression";
323 g_ptr_array_add(args,arg->str);
324 g_string_free(arg,FALSE);
326 arg = g_string_sized_new(32);
331 g_string_append_c(arg,c);
334 *error = "end of filter in the middle of a macro expression";
338 g_string_append_c(arg,c);
342 g_ptr_array_add(args,arg->str);
343 g_ptr_array_add(args,NULL);
345 g_string_free(arg,FALSE);
348 resolved = dfilter_macro_resolve(name->str, (gchar**)args->pdata, error);
349 if (*error) goto on_error;
353 g_string_append(out,resolved);
371 gchar* resolved = dfilter_macro_apply(out->str, depth++, error);
372 g_string_free(out,TRUE);
373 return (*error) ? NULL : resolved;
375 gchar* out_str = ep_strdup(out->str);
376 g_string_free(out,TRUE);
383 if (! *error) *error = "unknown error in macro expression";
384 g_string_free(out,TRUE);
389 static void macro_update(void* mp, const gchar** error) {
390 dfilter_macro_t* m = mp;
403 for (i = 0; i < num_macros; i++) {
404 if (m == &(macros[i])) continue;
406 if ( g_str_equal(m->name,macros[i].name) ) {
407 *error = ep_strdup_printf("macro '%s' exists already", m->name);
413 parts = g_ptr_array_new();
414 args_pos = g_array_new(FALSE,FALSE,sizeof(int));
416 m->priv = part = w = g_strdup(m->text);
418 g_ptr_array_add(parts,part);
438 if (c >= '0' && c <= '9') {
452 argc = argc < arg_pos ? arg_pos : argc;
454 g_array_append_val(args_pos,arg_pos);
455 g_ptr_array_add(parts,w);
466 g_ptr_array_add(parts,NULL);
468 if (m->parts) g_free(m->parts);
470 m->parts = (gchar**)parts->pdata;
472 if (m->args_pos) g_free(m->args_pos);
474 m->args_pos = (int*)(void *)args_pos->data;
476 g_ptr_array_free(parts,FALSE);
477 g_array_free(args_pos,FALSE);
490 static void macro_free(void* r) {
491 dfilter_macro_t* m = r;
502 static void* macro_copy(void* dest, const void* orig, unsigned len _U_) {
503 dfilter_macro_t* d = dest;
504 const dfilter_macro_t* m = orig;
508 d->name = g_strdup(m->name);
509 d->text = g_strdup(m->text);
510 d->usable = m->usable;
516 * Copy the contents of m->priv (a "cooked" version
517 * of m->text) into d->priv.
519 * First we clone m->text into d->priv, this gets
520 * us a NUL terminated string of the proper length.
522 * Then we loop copying bytes from m->priv into
523 * d-priv. Since m->priv contains internal ACSII NULs
524 * we use the length of m->text to stop the copy.
527 d->priv = g_strdup(m->text);
529 const gchar* oldText = m->text;
530 const gchar* oldPriv = m->priv;
531 gchar* newPriv = d->priv;
532 while(oldText && *oldText) {
533 *(newPriv++) = *(oldPriv++);
539 * The contents of the m->parts array contains pointers
540 * into various sections of m->priv. Since it's
541 * an argv style array of ponters, this array is
542 * actually one larger than the number of parts
543 * to hold the final NULL terminator.
545 * The following copy clones the original m->parts
546 * array into d->parts but then fixes-up the pointers
547 * so that they point into the appropriate sections
551 do nparts++; while (m->parts[nparts]);
552 d->parts = g_memdup(m->parts,(nparts+1)*sizeof(void*));
554 while(m->parts[nparts]) {
556 d->parts[nparts] = d->parts[nparts - 1] + (m->parts[nparts] - m->parts[nparts - 1]);
558 d->parts[nparts] = d->priv;
564 * Clone the contents of m->args_pos into d->args_pos.
567 d->args_pos = g_memdup(m->args_pos,(--nparts)*sizeof(int));
575 static gboolean macro_name_chk(void* r _U_, const char* in_name, unsigned name_len, void* u1 _U_, void* u2 _U_, const char** error) {
579 *error = "invalid name";
583 for (i=0; i < name_len; i++) {
584 if (!(in_name[i] == '_' || isalnum((guchar)in_name[i]) ) ) {
585 *error = "invalid char in name";
593 UAT_CSTRING_CB_DEF(macro,name,dfilter_macro_t)
594 UAT_CSTRING_CB_DEF(macro,text,dfilter_macro_t)
596 void dfilter_macro_init(void) {
597 static uat_field_t uat_fields[] = {
598 UAT_FLD_CSTRING_OTHER(macro,name,"Name",macro_name_chk,"The name of the macro."),
599 UAT_FLD_CSTRING_ISPRINT(macro,text,"Text","The text this macro resolves to."),
603 dfilter_macro_uat = uat_new("Display Filter Macros",
604 sizeof(dfilter_macro_t),
605 DFILTER_MACRO_FILENAME,
610 "ChDisplayFilterMacrosSection",
616 fvt_cache = g_hash_table_new(g_str_hash,g_str_equal);
619 void dfilter_macro_get_uat(void** p) {
620 *p = dfilter_macro_uat;
623 #ifdef DUMP_DFILTER_MACRO
625 * The dfilter_macro_t has several characteristics that are
626 * not immediattly obvious. The dump_dfilter_filter_macro_t()
627 * function can be used to help "visualize" the contents of
630 * Some non-obvious components of this struct include:
632 * m->parts is an argv style array of pointers into the
635 * The last pointer of an m->parts array should contain
636 * NULL to indicate the end of the parts pointer array.
638 * m->priv is a "cooked" copy of the m->text string.
639 * Any variable substitution indicators within m->text
640 * ("$1", "$2", ...) will have been replaced with ASCII
641 * NUL characters within m->priv.
643 * The first element of m->parts array (m-parts[0]) will
644 * usually have the same pointer value as m->priv (unless
645 * the dfilter-macro starts off with a variable
646 * substitution indicator (e.g. "$1").
649 void dump_dfilter_macro_t(const dfilter_macro_t *m, const char *function, const char *file, int line)
651 printf("\n<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
654 printf(" dfilter_macro_t * == NULL! (via: %s(): %s:%d)\n", function, file, line);
655 printf("\n>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
658 printf("DUMP of dfilter_macro_t: %p (via: %s(): %s:%d)\n", m, function, file, line);
660 printf(" &dfilter_macro->name == %p\n", &m->name);
661 if(m->name == NULL) {
662 printf(" ->name == NULL\n");
664 printf(" ->name == %p\n", m->name);
665 printf(" ->name == <%s>\n", m->name);
668 printf(" &dfilter_macro->text == %p\n", &m->text);
669 if(m->text == NULL) {
670 printf(" ->text == NULL\n");
672 printf(" ->text == %p\n", m->text);
673 printf(" ->text == <%s>\n", m->text);
676 printf(" &dfilter_macro->usable == %p\n", &m->usable);
677 printf(" ->usable == %u\n", m->usable);
679 printf(" &dfilter_macro->parts == %p\n", &m->parts);
681 if(m->parts == NULL) {
682 printf(" ->parts == NULL\n");
686 while (m->parts[i]) {
687 printf(" ->parts[%d] == %p\n", i, m->parts[i]);
688 printf(" ->parts[%d] == <%s>\n", i, m->parts[i]);
691 printf(" ->parts[%d] == NULL\n", i);
694 printf(" &dfilter_macro->args_pos == %p\n", &m->args_pos);
695 if(m->args_pos == NULL) {
696 printf(" ->args_pos == NULL\n");
698 printf(" ->args_pos == %p\n", m->args_pos);
699 /*printf(" ->args_pos == <%?>\n", m->args_pos);*/
702 printf(" &dfilter_macro->argc == %p\n", &m->argc);
703 printf(" ->argc == %d\n", m->argc);
705 printf(" &dfilter_macro->priv == %p\n", &m->priv);
706 if(m->priv == NULL) {
707 printf(" ->priv == NULL\n");
709 printf(" ->priv == %p\n", m->priv);
710 printf(" ->priv == <%s>\n", (char *)m->priv);
713 printf("\n>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");