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>
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 = 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 = 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) ) {
174 (e = 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 gchar* dfilter_macro_apply(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); \
244 args = NULL; } } while(0)
247 out = g_string_sized_new(64);
261 g_string_append_c(out,c);
269 args = g_ptr_array_new();
270 arg = g_string_sized_new(32);
271 name = g_string_sized_new(32);
277 g_string_append_c(out,'$');
281 g_string_append_c(out,'$');
282 g_string_append_c(out,c);
291 if ( isalnum((int)c) || c == '_' || c == '-' || c == '.' ) {
292 g_string_append_c(name,c);
293 } else if ( c == ':') {
295 } else if ( c == '}') {
298 g_ptr_array_add(args,NULL);
300 resolved = dfilter_macro_resolve(name->str, (gchar**)args->pdata, error);
301 if (*error) goto on_error;
305 g_string_append(out,resolved);
310 } else if ( c == '\0') {
311 *error = "end of filter in the middle of a macro expression";
314 *error = "invalid char in macro name";
321 *error = "end of filter in the middle of a macro expression";
324 g_ptr_array_add(args,arg->str);
325 g_string_free(arg,FALSE);
327 arg = g_string_sized_new(32);
332 g_string_append_c(arg,c);
335 *error = "end of filter in the middle of a macro expression";
339 g_string_append_c(arg,c);
343 g_ptr_array_add(args,arg->str);
344 g_ptr_array_add(args,NULL);
346 g_string_free(arg,FALSE);
349 resolved = dfilter_macro_resolve(name->str, (gchar**)args->pdata, error);
350 if (*error) goto on_error;
354 g_string_append(out,resolved);
372 gchar* resolved = dfilter_macro_apply(out->str, depth++, error);
373 g_string_free(out,TRUE);
374 return (*error) ? NULL : resolved;
376 gchar* out_str = ep_strdup(out->str);
377 g_string_free(out,TRUE);
384 if (! *error) *error = "unknown error in macro expression";
385 g_string_free(out,TRUE);
390 static void macro_update(void* mp, const gchar** error) {
391 dfilter_macro_t* m = mp;
404 for (i = 0; i < num_macros; i++) {
405 if (m == &(macros[i])) continue;
407 if ( g_str_equal(m->name,macros[i].name) ) {
408 *error = ep_strdup_printf("macro '%s' exists already", m->name);
414 /* Invalidate the display filter in case it's in use */
415 if (dfilter_macro_uat && dfilter_macro_uat->post_update_cb)
416 dfilter_macro_uat->post_update_cb();
418 parts = g_ptr_array_new();
419 args_pos = g_array_new(FALSE,FALSE,sizeof(int));
421 m->priv = part = w = g_strdup(m->text);
423 g_ptr_array_add(parts,part);
443 if (c >= '0' && c <= '9') {
457 argc = argc < arg_pos ? arg_pos : argc;
459 g_array_append_val(args_pos,arg_pos);
460 g_ptr_array_add(parts,w);
471 g_ptr_array_add(parts,NULL);
474 m->parts = (gchar**)parts->pdata;
477 m->args_pos = (int*)(void *)args_pos->data;
479 g_ptr_array_free(parts,FALSE);
480 g_array_free(args_pos,FALSE);
493 static void macro_free(void* r) {
494 dfilter_macro_t* m = r;
505 static void* macro_copy(void* dest, const void* orig, size_t len _U_) {
506 dfilter_macro_t* d = dest;
507 const dfilter_macro_t* m = orig;
511 d->name = g_strdup(m->name);
512 d->text = g_strdup(m->text);
513 d->usable = m->usable;
519 * Copy the contents of m->priv (a "cooked" version
520 * of m->text) into d->priv.
522 * First we clone m->text into d->priv, this gets
523 * us a NUL terminated string of the proper length.
525 * Then we loop copying bytes from m->priv into
526 * d-priv. Since m->priv contains internal ACSII NULs
527 * we use the length of m->text to stop the copy.
530 d->priv = g_strdup(m->text);
532 const gchar* oldText = m->text;
533 const gchar* oldPriv = m->priv;
534 gchar* newPriv = d->priv;
535 while(oldText && *oldText) {
536 *(newPriv++) = *(oldPriv++);
542 * The contents of the m->parts array contains pointers
543 * into various sections of m->priv. Since it's
544 * an argv style array of ponters, this array is
545 * actually one larger than the number of parts
546 * to hold the final NULL terminator.
548 * The following copy clones the original m->parts
549 * array into d->parts but then fixes-up the pointers
550 * so that they point into the appropriate sections
554 do nparts++; while (m->parts[nparts]);
555 d->parts = g_memdup(m->parts,(nparts+1)*(guint)sizeof(void*));
557 while(m->parts[nparts]) {
559 d->parts[nparts] = d->parts[nparts - 1] + (m->parts[nparts] - m->parts[nparts - 1]);
561 d->parts[nparts] = d->priv;
567 * Clone the contents of m->args_pos into d->args_pos.
570 d->args_pos = g_memdup(m->args_pos,(--nparts)*(guint)sizeof(int));
578 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) {
582 *error = "invalid name";
586 for (i=0; i < name_len; i++) {
587 if (!(in_name[i] == '_' || isalnum((guchar)in_name[i]) ) ) {
588 *error = "invalid char in name";
596 UAT_CSTRING_CB_DEF(macro,name,dfilter_macro_t)
597 UAT_CSTRING_CB_DEF(macro,text,dfilter_macro_t)
599 void dfilter_macro_init(void) {
600 static uat_field_t uat_fields[] = {
601 UAT_FLD_CSTRING_OTHER(macro,name,"Name",macro_name_chk,"The name of the macro."),
602 UAT_FLD_CSTRING_ISPRINT(macro,text,"Text","The text this macro resolves to."),
606 dfilter_macro_uat = uat_new("Display Filter Macros",
607 sizeof(dfilter_macro_t),
608 DFILTER_MACRO_FILENAME,
613 "ChDisplayFilterMacrosSection",
617 NULL, /* Note: This is set in macros_init () */
620 fvt_cache = g_hash_table_new(g_str_hash,g_str_equal);
623 void dfilter_macro_get_uat(void** p) {
624 *p = dfilter_macro_uat;
627 #ifdef DUMP_DFILTER_MACRO
629 * The dfilter_macro_t has several characteristics that are
630 * not immediattly obvious. The dump_dfilter_filter_macro_t()
631 * function can be used to help "visualize" the contents of
634 * Some non-obvious components of this struct include:
636 * m->parts is an argv style array of pointers into the
639 * The last pointer of an m->parts array should contain
640 * NULL to indicate the end of the parts pointer array.
642 * m->priv is a "cooked" copy of the m->text string.
643 * Any variable substitution indicators within m->text
644 * ("$1", "$2", ...) will have been replaced with ASCII
645 * NUL characters within m->priv.
647 * The first element of m->parts array (m-parts[0]) will
648 * usually have the same pointer value as m->priv (unless
649 * the dfilter-macro starts off with a variable
650 * substitution indicator (e.g. "$1").
653 void dump_dfilter_macro_t(const dfilter_macro_t *m, const char *function, const char *file, int line)
655 printf("\n<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
658 printf(" dfilter_macro_t * == NULL! (via: %s(): %s:%d)\n", function, file, line);
659 printf("\n>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
662 printf("DUMP of dfilter_macro_t: %p (via: %s(): %s:%d)\n", m, function, file, line);
664 printf(" &dfilter_macro->name == %p\n", &m->name);
665 if(m->name == NULL) {
666 printf(" ->name == NULL\n");
668 printf(" ->name == %p\n", m->name);
669 printf(" ->name == <%s>\n", m->name);
672 printf(" &dfilter_macro->text == %p\n", &m->text);
673 if(m->text == NULL) {
674 printf(" ->text == NULL\n");
676 printf(" ->text == %p\n", m->text);
677 printf(" ->text == <%s>\n", m->text);
680 printf(" &dfilter_macro->usable == %p\n", &m->usable);
681 printf(" ->usable == %u\n", m->usable);
683 printf(" &dfilter_macro->parts == %p\n", &m->parts);
685 if(m->parts == NULL) {
686 printf(" ->parts == NULL\n");
690 while (m->parts[i]) {
691 printf(" ->parts[%d] == %p\n", i, m->parts[i]);
692 printf(" ->parts[%d] == <%s>\n", i, m->parts[i]);
695 printf(" ->parts[%d] == NULL\n", i);
698 printf(" &dfilter_macro->args_pos == %p\n", &m->args_pos);
699 if(m->args_pos == NULL) {
700 printf(" ->args_pos == NULL\n");
702 printf(" ->args_pos == %p\n", m->args_pos);
703 /*printf(" ->args_pos == <%?>\n", m->args_pos);*/
706 printf(" &dfilter_macro->argc == %p\n", &m->argc);
707 printf(" ->argc == %d\n", m->argc);
709 printf(" &dfilter_macro->priv == %p\n", &m->priv);
710 if(m->priv == NULL) {
711 printf(" ->priv == NULL\n");
713 printf(" ->priv == %p\n", m->priv);
714 printf(" ->priv == <%s>\n", (char *)m->priv);
717 printf("\n>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");