diff options
Diffstat (limited to 'epan/dfilter/dfilter.c')
-rw-r--r-- | epan/dfilter/dfilter.c | 352 |
1 files changed, 352 insertions, 0 deletions
diff --git a/epan/dfilter/dfilter.c b/epan/dfilter/dfilter.c new file mode 100644 index 0000000000..a8d249cbf4 --- /dev/null +++ b/epan/dfilter/dfilter.c @@ -0,0 +1,352 @@ +/* dfilter.c + * Main entry point for dfilter routines + * + * $Id: dfilter.c,v 1.1 2001/02/01 20:21:18 gram Exp $ + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdio.h> + +#ifdef NEED_SNPRINTF_H +#include "snprintf.h" +#endif + +#include "dfilter-int.h" +#include "syntax-tree.h" +#include "gencode.h" +#include "semcheck.h" +#include "dfvm.h" + + +/* Balanced tree of abbreviations and IDs */ +GTree *dfilter_tokens = NULL; + +#define DFILTER_TOKEN_ID_OFFSET 1 + +/* Comparision function for tree insertion. A wrapper around strcmp() */ +static int g_strcmp(gconstpointer a, gconstpointer b); + +/* Global error message space for dfilter_compile errors */ +gchar dfilter_error_msg_buf[1024]; +gchar *dfilter_error_msg; /* NULL when no error resulted */ + +/* In proto.c */ +extern int hf_text_only; + +/* From scanner.c */ +void df_scanner_text(const char *text); +void df_scanner_file(FILE *fh); +void df_scanner_cleanup(void); +int df_lex(void); + +/* Holds the singular instance of our Lemon parser object */ +void* ParserObj = NULL; + +void +dfilter_fail(char *format, ...) +{ + va_list args; + + /* If we've already reported one error, don't overwite it */ + if (dfilter_error_msg != NULL) + return; + + va_start(args, format); + + vsnprintf(dfilter_error_msg_buf, sizeof(dfilter_error_msg_buf), + format, args); + dfilter_error_msg = dfilter_error_msg_buf; + va_end(args); +} + + +/* Initialize the dfilter module */ +void +dfilter_init(void) +{ + int id, num_symbols; + char *abbrev; + header_field_info *hfinfo, *same_name_hfinfo; + + num_symbols = proto_registrar_n(); + + if (dfilter_tokens) { + /* XXX - needed? */ + g_message("I expected hf_ids to be NULL\n"); + g_tree_destroy(dfilter_tokens); + + /* Make sure the hfinfo->same_name links are broken */ + for (id = 0; id < num_symbols; id++) { + hfinfo = proto_registrar_get_nth(id); + hfinfo->same_name = NULL; + } + } + dfilter_tokens = g_tree_new(g_strcmp); + + /* Populate the abbrev/ID GTree (header-field symbol table) */ + + + for (id = 0; id < num_symbols; id++) { + if (id == hf_text_only) { + continue; + } + abbrev = proto_registrar_get_abbrev(id); + hfinfo = proto_registrar_get_nth(id); + + g_assert(abbrev); /* Not Null */ + g_assert(abbrev[0] != 0); /* Not empty string */ + + /* We allow multiple hfinfo's to be registered under the same + * abbreviation. This was done for X.25 */ + same_name_hfinfo = g_tree_lookup(dfilter_tokens, abbrev); + if (same_name_hfinfo) { + /* Set the "same_name" pointer in the hfinfo, then + * allow the code after this if{} block to replace the + * old hfinfo with the new hfinfo in the GTree. Thus, + * we end up with a linked-list of same-named hfinfo's, + * with the root of the list being the hfinfo in the GTree */ + hfinfo->same_name = same_name_hfinfo; + + } + g_tree_insert(dfilter_tokens, abbrev, hfinfo); + } + + 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); + + /* Initialize the syntax-tree sub-sub-system */ + sttype_init(); +} + +/* Clean-up the dfilter module */ +void +dfilter_cleanup(void) +{ + /* Free the abbrev/ID GTree */ + if (dfilter_tokens) { + g_tree_destroy(dfilter_tokens); + dfilter_tokens = NULL; + } + + /* Free the Lemon Parser object */ + if (ParserObj) { + DfilterFree(ParserObj, g_free); + } + + /* Clean up the syntax-tree sub-sub-system */ + sttype_cleanup(); +} + + + +/* Lookup an abbreviation in our token tree, returing the ID # + * If the abbreviation doesn't exit, returns -1 */ +header_field_info* +dfilter_lookup_token(char *abbrev) +{ + g_assert(abbrev != NULL); + return g_tree_lookup(dfilter_tokens, abbrev); +} + +/* String comparison func for dfilter_token GTree */ +static int +g_strcmp(gconstpointer a, gconstpointer b) +{ + return strcmp((const char*)a, (const char*)b); +} + +static dfilter_t* +dfilter_new(void) +{ + dfilter_t *df; + + df = g_new(dfilter_t, 1); + df->insns = NULL; + + return df; +} + +/* Given a GPtrArray of instructions (dfvm_insn_t), + * free them. */ +static void +free_insns(GPtrArray *insns) +{ + int i; + dfvm_insn_t *insn; + + for (i = 0; i < insns->len; i++) { + insn = g_ptr_array_index(insns, i); + dfvm_insn_free(insn); + } +} + +void +dfilter_free(dfilter_t *df) +{ + if (df->insns) { + free_insns(df->insns); + } + + g_free(df->registers); + g_free(df->attempted_load); + g_free(df); +} + + +static dfwork_t* +dfwork_new(void) +{ + dfwork_t *dfw; + + dfw = g_new(dfwork_t, 1); + + dfw->st_root = NULL; + dfw->syntax_error = FALSE; + dfw->insns = NULL; + dfw->loaded_fields = NULL; + dfw->next_insn_id = 0; + dfw->next_register = 0; + + 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); + } + + if (dfw->insns) { + free_insns(dfw->insns); + } + + g_free(dfw); +} + + +gboolean +dfilter_compile(gchar *text, dfilter_t **dfp) +{ + int token; + dfilter_t *dfilter; + dfwork_t *dfw; + + dfilter_error_msg = NULL; + + dfw = dfwork_new(); + + df_scanner_text(text); + + while (1) { + df_lval = stnode_new(STTYPE_UNINITIALIZED, NULL); + token = df_lex(); + + /* Check for end-of-input */ + if (token == 0) { + /* Tell the parser that we have reached the end of input */ + Dfilter(ParserObj, 0, NULL, dfw); + + /* Free the stnode_t that we just generated, since + * the parser doesn't know about it and won't free it + * for us. */ + stnode_free(df_lval); + df_lval = NULL; + break; + } + + /* Give the token to the parser */ + Dfilter(ParserObj, token, df_lval, dfw); + + if (dfw->syntax_error) { + break; + } + } + + /* One last check for syntax error (after EOF) */ + if (dfw->syntax_error) { + goto FAILURE; + } + + + /* Success, but was it an empty filter? If so, discard + * it and set *dfp to NULL */ + if (dfw->st_root == NULL) { + *dfp = NULL; + } + else { + + /* Check semantics and do necessary type conversion*/ + if (!dfw_semcheck(dfw)) { + goto FAILURE; + } + + /* Create bytecode */ + dfw_gencode(dfw); + + /* Tuck away the bytecode in the dfilter_t */ + dfilter = dfilter_new(); + dfilter->insns = dfw->insns; + dfw->insns = NULL; + + /* Initialize run-time space */ + dfilter->num_registers = dfw->next_register; + dfilter->registers = g_new0(GList*, dfilter->num_registers); + dfilter->attempted_load = g_new0(gboolean, dfilter->num_registers); + + /* And give it to the user. */ + *dfp = dfilter; + } + /* SUCCESS */ + dfwork_free(dfw); + + /* Reset flex */ + df_scanner_cleanup(); + + return TRUE; + +FAILURE: + if (dfw) { + dfwork_free(dfw); + } + dfilter_fail("Unable to parse filter string \"%s\".", text); + *dfp = NULL; + + /* Reset flex */ + df_scanner_cleanup(); + return FALSE; + +} + + +gboolean +dfilter_apply(dfilter_t *df, tvbuff_t *tvb, proto_tree *tree) +{ + return dfvm_apply(df, tvb, tree); +} + +gboolean +dfilter_apply_edt(dfilter_t *df, epan_dissect_t* edt) +{ + return dfvm_apply(df, edt->tvb, edt->tree); +} + + +void +dfilter_dump(dfilter_t *df) +{ + dfvm_dump(stdout, df->insns); +} |