%include { /* mate_grammar.lemon * MATE's configuration language grammar * * Copyright 2005, Luis E. Garcia Ontanon * * $Id$ * * Ethereal - Network traffic analyzer * By Gerald Combs * Copyright 1998 Gerald Combs * * 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. * * 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "mate.h" #include "mate_grammar.h" #define DUMMY void* typedef struct _extraction { gchar* as; header_field_info* hfi; struct _extraction* next; struct _extraction* last; } extraction_t; typedef struct _pdu_flags { gboolean drop_unassigned; gboolean discard; gboolean last_extracted; } pdu_flags_t; typedef struct _pdu_criteria_t { AVPL* criterium_avpl; avpl_match_mode criterium_match_mode; accept_mode_t criterium_accept_mode; } pdu_criteria_t; typedef struct _pdu_statement { GPtrArray* payload; pdu_flags_t* flags; extraction_t* extraction; pdu_criteria_t* criteria; GPtrArray* transforms; } pdu_statement_t; typedef struct _gop_tree_statement { gop_tree_mode_t pdu_tree_mode; gboolean drop_unassigned; gboolean show_times; } gop_tree_statement; typedef struct _gop_timer_statement { float expiration; float idle_timeout; float lifetime; } gop_timer_statement; typedef struct _gop_option_statement { gop_timer_statement* timer_sts; gop_tree_statement* tree_sts; } gop_option_statement; typedef struct _gop_control_statement { AVPL* start; AVPL* stop; AVPL* extras; } gop_control_statement; typedef struct _gop_statement { gop_control_statement* control; gop_option_statement* options; GPtrArray* transforms; } gop_statement; typedef struct _gog_statements { float expiration; gop_tree_mode_t gop_tree_mode; GPtrArray* transform_list; AVPL* extras; LoAL* current_gogkeys; } gog_statement_t; static void configuration_error(mate_config* mc, const gchar* fmt, ...) { static gchar error_buffer[256]; const gchar* incl; gint i; mate_config_frame* current_frame; va_list list; va_start( list, fmt ); g_vsnprintf(error_buffer,sizeof(error_buffer),fmt,list); va_end( list ); i = (gint) mc->config_stack->len; while (i--) { if (i>0) { incl = "\n included from: "; } else { incl = " "; } current_frame = g_ptr_array_index(mc->config_stack,(guint)i); g_string_sprintfa(mc->config_error,"%s%s at line %u",incl, current_frame->filename, current_frame->linenum); } g_string_sprintfa(mc->config_error,": %s\n",error_buffer); THROW(MateConfigError); } static AVPL_Transf* new_transform_elem(AVPL* match, AVPL* replace, avpl_match_mode match_mode, avpl_replace_mode replace_mode) { AVPL_Transf* t = g_malloc(sizeof(AVPL_Transf)); t->name = NULL; t->match = match; t->replace = replace; t->match_mode = match_mode; t->replace_mode = replace_mode; t->map = NULL; t->next = NULL; return t; } static pdu_statement_t* do_pdu_statements(GPtrArray* payload, pdu_flags_t* flags, extraction_t* extraction, pdu_criteria_t* criteria, GPtrArray* transforms) { pdu_statement_t* s = g_malloc(sizeof(pdu_statement_t)); s->payload = payload; s->flags = flags; s->extraction = extraction; s->criteria = criteria; s->transforms = transforms; return s; } static gchar* recolonize(mate_config* mc, gchar* s) { GString* str = g_string_new(""); gchar** vec; gchar* r; guint i,v; gchar c; vec = g_strsplit(s,":",0); for (i = 0; vec[i]; i++) { g_strdown(vec[i]); v = 0; switch ( strlen(vec[i]) ) { case 2: c = vec[i][1]; vec[i][1] = vec[i][0]; vec[i][0] = c; if (vec[i][0] >= '0' && vec[i][0] <= '9') { v += (vec[i][1] - '0' )*16; } else { v += (vec[i][1] - 'a' + 10)*16; } case 1: if (vec[i][0] >= '0' && vec[i][0] <= '9') { v += (vec[i][0] - '0' ); } else { v += (vec[i][0] - 'a' + 10); } case 0: break; default: configuration_error(mc,"bad token %s",s); } g_string_sprintfa(str,":%.2X",v); } g_strfreev(vec); g_string_erase(str,0,1); r = str->str; g_string_free(str,FALSE); return r; } } %name MateParser %token_prefix TOKEN_ %token_type { gchar* } %token_destructor { if ($$) g_free($$); } %extra_argument { mate_config* mc } %syntax_error { configuration_error(mc,"Syntax Error before %s",yyminor); } %parse_failure { configuration_error(mc,"Parse Error"); } %type transform_decl { AVPL_Transf* } %type transform_body { AVPL_Transf* } %type transform_statements { AVPL_Transf* } %type transform_statement { AVPL_Transf* } %type transform_blks { AVPL_Transf* } %type transform_blk { AVPL_Transf* } %type match_mode { avpl_match_mode } %type action_mode { avpl_replace_mode } %type gop_name { gchar* } %type time_value { float } %type pdu_name { gchar* } %type gop_tree_mode { gop_tree_mode_t } %type true_false { gboolean } %type pdu_setup { pdu_statement_t* } %type pdu_statements { pdu_statement_t* } %type pdu_criteria_statement { pdu_criteria_t* } %type pdu_flag_statements { pdu_flags_t* } %type accept_mode { accept_mode_t } %type drop_unassigned_statement { gboolean } %type discard_pdu_data_statement { gboolean } %type last_extracted_statement { gboolean } %type extraction_statement {extraction_t*} %type extraction_statements {extraction_t*} %type gop_setup { gop_statement* } %type gop_statements { gop_statement* } %type gop_control_statements { gop_control_statement* } %type gop_option_statements { gop_option_statement* } %type gop_timer_statements { gop_timer_statement* } %type gop_tree_statements { gop_tree_statement* } %type gop_start_statement { AVPL* } %type gop_stop_statement { AVPL* } %type extra_statement { AVPL* } %type show_goptree_statement { gop_tree_mode_t } %type show_times_statement { gboolean } %type expiration_statement { float } %type idle_timeout_statement { float } %type lifetime_statement { float } %type gog_statements { gog_statement_t* } %type gog_goptree_statement { gop_tree_mode_t } %type gog_key_statements { LoAL* } %type gog_key_statement { AVPL* } %type transform_list_statement { GPtrArray* } %type transform { AVPL_Transf* } %type gop_tree_type { gop_tree_mode_t } %type payload_statement { GPtrArray* } %type proto_stack { GPtrArray* } %type field { header_field_info* } %type transform_list { GPtrArray* } %type avpl { AVPL* } %type avps { AVPL* } %type avp { AVP* } %type value { gchar* } %type avp_oneoff { gchar* } mate_config ::= decls DONE_KW SEMICOLON. decls ::= decls decl. decls ::= decl. decl ::= pdu_decl. decl ::= gop_decl. decl ::= gog_decl. decl ::= transform_decl. /******************************************* TRANSFORM */ transform_decl(A) ::= TRANSFORM_KW NAME(B) transform_body(C) SEMICOLON. { AVPL_Transf* c; if ( g_hash_table_lookup(mc->transfs,B) ) { configuration_error(mc,"A transformation called '%s' exists already",B); } for ( c = C; c; c = c->next ) c->name = g_strdup(B); g_hash_table_insert(mc->transfs,C->name,C); A = NULL; } transform_body(A) ::= OPEN_BRACE transform_blks(B) CLOSE_BRACE. { A = B; } transform_blks(A) ::= transform_blks(C) transform_blk(B). { AVPL_Transf* c; for ( c = C; c->next; c = c->next ) ; c->next = B; A = C; } transform_blks(A) ::= transform_blk(B). { A = B; } transform_blk(A) ::= MATCH_KW match_mode(B) avpl(C) action_mode(D) avpl(E) SEMICOLON. { A = new_transform_elem(C,E,B,D); } transform_blk(A) ::= MATCH_KW match_mode(B) avpl(C) SEMICOLON. { A = new_transform_elem(C,new_avpl(""),B,AVPL_INSERT); } transform_blk(A) ::= MATCH_KW avpl(B) action_mode(C) avpl(D) SEMICOLON. { A = new_transform_elem(B,D,AVPL_STRICT,C); } transform_blk(A) ::= action_mode(B) avpl(C) SEMICOLON. { A = new_transform_elem(new_avpl(""),C,AVPL_NO_MATCH,B); } transform_blk(A) ::= MATCH_KW avpl(B) SEMICOLON. { A = new_transform_elem(B,new_avpl(""),AVPL_STRICT,AVPL_INSERT); } match_mode(A) ::= STRICT_KW. { A = AVPL_STRICT; } match_mode(A) ::= EVERY_KW. { A = AVPL_EVERY; } match_mode(A) ::= LOOSE_KW. { A = AVPL_LOOSE; } action_mode(A) ::= REPLACE_KW. { A = AVPL_REPLACE; } action_mode(A) ::= INSERT_KW. { A = AVPL_INSERT; } /******************************************* PDU */ pdu_decl ::= PDU_KW NAME(NAME) PROTO_KW field(FIELD) TRANSPORT_KW proto_stack(STACK) pdu_setup(SETUP) SEMICOLON. { mate_cfg_pdu* cfg = new_pducfg(NAME); extraction_t *extraction, *next_extraction; GPtrArray* transport_stack = g_ptr_array_new(); int i; if (! cfg ) configuration_error(mc,"could not create Pdu %s.",NAME); cfg->hfid_proto = FIELD->id; cfg->last_extracted = (SETUP->flags) ? SETUP->flags->last_extracted : mc->defaults.pdu.last_extracted; cfg->discard = (SETUP->flags) ? SETUP->flags->discard : mc->defaults.pdu.discard; cfg->drop_unassigned = (SETUP->flags) ? SETUP->flags->drop_unassigned : mc->defaults.pdu.drop_unassigned; g_string_sprintfa(mc->protos_filter,"||%s",FIELD->abbrev); /* flip the transport_stack */ for (i = STACK->len - 1; STACK->len; i--) { g_ptr_array_add(transport_stack,g_ptr_array_remove_index(STACK,i)); } g_ptr_array_free(STACK,FALSE); cfg->transport_ranges = transport_stack; cfg->payload_ranges = SETUP->payload; if (SETUP->criteria) { cfg->criterium = SETUP->criteria->criterium_avpl; cfg->criterium_match_mode = SETUP->criteria->criterium_match_mode; cfg->criterium_accept_mode = SETUP->criteria->criterium_accept_mode; } cfg->transforms = SETUP->transforms ? SETUP->transforms : g_ptr_array_new(); for (extraction = SETUP->extraction; extraction; extraction = next_extraction) { next_extraction = extraction->next; if ( ! add_hfid(extraction->hfi, extraction->as, cfg->hfids_attr) ) { configuration_error(mc,"MATE: failed to create extraction rule '%s'",extraction->as); } g_free(extraction); } } pdu_setup(A) ::= OPEN_BRACE pdu_statements(B) CLOSE_BRACE. { A = B; } pdu_statements(A) ::= payload_statement(B) pdu_flag_statements(C) extraction_statements(D) pdu_criteria_statement(E) transform_list_statement(F). { A = do_pdu_statements(B,C,D,E,F); } pdu_statements(A) ::= payload_statement(B) pdu_flag_statements(C) extraction_statements(D) pdu_criteria_statement(E). { A = do_pdu_statements(B,C,D,E,NULL); } pdu_statements(A) ::= payload_statement(B) pdu_flag_statements(C) extraction_statements(D) transform_list_statement(F). { A = do_pdu_statements(B,C,D,NULL,F); } pdu_statements(A) ::= payload_statement(B) pdu_flag_statements(C) extraction_statements(D). { A = do_pdu_statements(B,C,D,NULL,NULL); } pdu_statements(A) ::= payload_statement(B) extraction_statements(D) pdu_criteria_statement(E) transform_list_statement(F). { A = do_pdu_statements(B,NULL,D,E,F); } pdu_statements(A) ::= payload_statement(B) extraction_statements(D) pdu_criteria_statement(E). { A = do_pdu_statements(B,NULL,D,E,NULL); } pdu_statements(A) ::= payload_statement(B) extraction_statements(D) transform_list_statement(F). { A = do_pdu_statements(B,NULL,D,NULL,F); } pdu_statements(A) ::= payload_statement(B) extraction_statements(D). { A = do_pdu_statements(B,NULL,D,NULL,NULL); } pdu_statements(A) ::= pdu_flag_statements(C) extraction_statements(D) pdu_criteria_statement(E) transform_list_statement(F). { A = do_pdu_statements(NULL,C,D,E,F); } pdu_statements(A) ::= pdu_flag_statements(C) extraction_statements(D) pdu_criteria_statement(E). { A = do_pdu_statements(NULL,C,D,E,NULL); } pdu_statements(A) ::= pdu_flag_statements(C) extraction_statements(D) transform_list_statement(F). { A = do_pdu_statements(NULL,C,D,NULL,F); } pdu_statements(A) ::= pdu_flag_statements(C) extraction_statements(D). { A = do_pdu_statements(NULL,C,D,NULL,NULL); } pdu_statements(A) ::= extraction_statements(D) pdu_criteria_statement(E) transform_list_statement(F). { A = do_pdu_statements(NULL,NULL,D,E,F); } pdu_statements(A) ::= extraction_statements(D) pdu_criteria_statement(E). { A = do_pdu_statements(NULL,NULL,D,E,NULL); } pdu_statements(A) ::= extraction_statements(D) transform_list_statement(F). { A = do_pdu_statements(NULL,NULL,D,NULL,F); } pdu_statements(A) ::= extraction_statements(D). { A = do_pdu_statements(NULL,NULL,D,NULL,NULL); } pdu_flag_statements(A) ::= drop_unassigned_statement(B) discard_pdu_data_statement(C) last_extracted_statement(D). { A = g_malloc(sizeof(pdu_flags_t)); A->drop_unassigned = B; A->discard = C; A->last_extracted = D; } pdu_flag_statements(A) ::= drop_unassigned_statement(B) discard_pdu_data_statement(C). { A = g_malloc(sizeof(pdu_flags_t)); A->drop_unassigned = B; A->discard = C; A->last_extracted = mc->defaults.pdu.last_extracted; } pdu_flag_statements(A) ::= drop_unassigned_statement(B) last_extracted_statement(D). { A = g_malloc(sizeof(pdu_flags_t)); A->drop_unassigned = B; A->discard = mc->defaults.pdu.discard; A->last_extracted = D; } pdu_flag_statements(A) ::= discard_pdu_data_statement(C) last_extracted_statement(D). { A = g_malloc(sizeof(pdu_flags_t)); A->drop_unassigned = mc->defaults.pdu.drop_unassigned; A->discard = C; A->last_extracted = D; } pdu_flag_statements(A) ::= last_extracted_statement(D). { A = g_malloc(sizeof(pdu_flags_t)); A->drop_unassigned = mc->defaults.pdu.drop_unassigned; A->discard = mc->defaults.pdu.discard; A->last_extracted = D; } pdu_flag_statements(A) ::= discard_pdu_data_statement(C). { A = g_malloc(sizeof(pdu_flags_t)); A->drop_unassigned = mc->defaults.pdu.drop_unassigned; A->discard = C; A->last_extracted = mc->defaults.pdu.last_extracted; } pdu_flag_statements(A) ::= drop_unassigned_statement(B). { A = g_malloc(sizeof(pdu_flags_t)); A->drop_unassigned = B; A->discard = mc->defaults.pdu.discard; A->last_extracted = mc->defaults.pdu.last_extracted; } payload_statement(A) ::= PAYLOAD_KW proto_stack(B) SEMICOLON. { A = B; } pdu_criteria_statement(A) ::= CRITERIA_KW accept_mode(B) match_mode(C) avpl(D) SEMICOLON. { A = g_malloc(sizeof(pdu_criteria_t)); A->criterium_avpl = D; A->criterium_match_mode = C; A->criterium_accept_mode = B; } accept_mode(A) ::= ACCEPT_KW. { A = ACCEPT_MODE; } accept_mode(A) ::= REJECT_KW. { A = REJECT_MODE; } extraction_statements(A) ::= extraction_statements(B) extraction_statement(C). { A = B; A->last->next = C; A->last = C; } extraction_statements(A) ::= extraction_statement(B). { A = B; A->last = A; } extraction_statement(A) ::= EXTRACT_KW NAME(NAME) FROM_KW field(FIELD) SEMICOLON. { A = g_malloc(sizeof(extraction_t)); A->as = NAME; A->hfi = FIELD; A->next = A->last = NULL; } drop_unassigned_statement(A) ::= DROP_UNASSIGNED_KW true_false(B) SEMICOLON. { A = B; } discard_pdu_data_statement(A) ::= DISCARD_PDU_DATA_KW true_false(B) SEMICOLON. { A = B; } last_extracted_statement(A) ::= LAST_PDU_KW true_false(B) SEMICOLON. { A = B; } proto_stack(A) ::= proto_stack(B) SLASH field(C). { int* hfidp = g_malloc(sizeof(int)); g_string_sprintfa(mc->fields_filter,"||%s",C->abbrev); *hfidp = C->id; g_ptr_array_add(B,hfidp); A = B; } proto_stack(A) ::= field(B). { int* hfidp = g_malloc(sizeof(int)); *hfidp = B->id; g_string_sprintfa(mc->fields_filter,"||%s",B->abbrev); A = g_ptr_array_new(); g_ptr_array_add(A,hfidp); } field(A) ::= NAME(B). { A = proto_registrar_get_byname(B); } /******************************************* GOP */ gop_decl(A) ::= GOP_KW NAME(B) ON_KW pdu_name(C) MATCH_KW avpl(D) gop_setup(E) SEMICOLON. { mate_cfg_gop* cfg; if (g_hash_table_lookup(mc->gopcfgs,B)) configuration_error(mc,"A Gop Named '%s' exists already.",B); if (g_hash_table_lookup(mc->gops_by_pduname,C) ) configuration_error(mc,"Gop for Pdu '%s' exists already",C); cfg = new_gopcfg(B); g_hash_table_insert(mc->gops_by_pduname,C,cfg); g_hash_table_insert(mc->gopcfgs,cfg->name,cfg); cfg->on_pdu = C; cfg->drop_unassigned = (E->options && E->options->tree_sts) ? E->options->tree_sts->drop_unassigned : mc->defaults.gop.drop_unassigned; cfg->show_times = (E->options && E->options->tree_sts) ? E->options->tree_sts->show_times : mc->defaults.gop.show_times; cfg->pdu_tree_mode = (E->options && E->options->tree_sts) ? E->options->tree_sts->pdu_tree_mode : mc->defaults.gop.pdu_tree_mode; cfg->expiration = (E->options && E->options->timer_sts) ? E->options->timer_sts->expiration : mc->defaults.gop.expiration; cfg->idle_timeout = (E->options && E->options->timer_sts) ? E->options->timer_sts->idle_timeout : mc->defaults.gop.idle_timeout; cfg->lifetime = (E->options && E->options->timer_sts) ? E->options->timer_sts->lifetime : mc->defaults.gop.lifetime; cfg->start = E->control ? E->control->start : NULL; cfg->stop = E->control ? E->control->stop : NULL; cfg->key = D; cfg->transforms = (E->transforms) ? E->transforms : g_ptr_array_new(); if (E->control && E->control->extras) { merge_avpl(cfg->extra,E->control->extras,TRUE); delete_avpl(E->control->extras,TRUE); } if (E->control) g_free(E->control); if (E->options) { if (E->options->tree_sts) g_free(E->options->tree_sts); if (E->options->timer_sts) g_free(E->options->timer_sts); if (E->options) g_free(E->options); } g_free(E); } gop_decl(A) ::= GOP_KW NAME(B) ON_KW pdu_name(C) MATCH_KW avpl(D) SEMICOLON. { mate_cfg_gop* cfg; if (g_hash_table_lookup(mc->gopcfgs,B)) configuration_error(mc,"A Gop Named '%s' exists already.",B); if (g_hash_table_lookup(mc->gops_by_pduname,C) ) configuration_error(mc,"Gop for Pdu '%s' exists already",C); cfg = new_gopcfg(B); g_hash_table_insert(mc->gops_by_pduname,C,cfg); g_hash_table_insert(mc->gopcfgs,cfg->name,cfg); cfg->drop_unassigned = mc->defaults.gop.drop_unassigned; cfg->show_times = mc->defaults.gop.show_times; cfg->pdu_tree_mode = mc->defaults.gop.pdu_tree_mode; cfg->expiration = mc->defaults.gop.expiration; cfg->idle_timeout = mc->defaults.gop.idle_timeout; cfg->lifetime = mc->defaults.gop.lifetime; cfg->start = NULL; cfg->stop = NULL; cfg->key = D; cfg->transforms = g_ptr_array_new(); } gop_setup(A) ::= OPEN_BRACE gop_statements(B) CLOSE_BRACE. { A = B; } gop_statements(A) ::= gop_control_statements(B) gop_option_statements(C) transform_list_statement(E). { A = g_malloc(sizeof(gop_statement)); A->control = B; A->options = C; A->transforms = E; } gop_statements(A) ::= gop_option_statements(C) transform_list_statement(E). { A = g_malloc(sizeof(gop_statement)); A->control = NULL; A->options = C; A->transforms = E; } gop_statements(A) ::= gop_control_statements(B) transform_list_statement(E). { A = g_malloc(sizeof(gop_statement)); A->control = B; A->options = NULL; A->transforms = E; } gop_statements(A) ::= gop_control_statements(B) gop_option_statements(C). { A = g_malloc(sizeof(gop_statement)); A->control = B; A->options = C; A->transforms = NULL; } gop_statements(A) ::= gop_option_statements(C). { A = g_malloc(sizeof(gop_statement)); A->control = NULL; A->options = C; A->transforms = NULL; } gop_statements(A) ::= gop_control_statements(B). { A = g_malloc(sizeof(gop_statement)); A->control = B; A->options = NULL; A->transforms = NULL; } gop_statements(A) ::= transform_list_statement(E). { A = g_malloc(sizeof(gop_statement)); A->control = NULL; A->options = NULL; A->transforms = E; } gop_control_statements(A) ::= gop_start_statement(B) gop_stop_statement(C) extra_statement(D).{ A = g_malloc(sizeof(gop_control_statement)); A->start = B; A->stop = C; A->extras = D; } gop_control_statements(A) ::= gop_stop_statement(C) extra_statement(D).{ A = g_malloc(sizeof(gop_control_statement)); A->start = NULL; A->stop = C; A->extras = D; } gop_control_statements(A) ::= gop_start_statement(B) extra_statement(D).{ A = g_malloc(sizeof(gop_control_statement)); A->start = B; A->stop = NULL; A->extras = D; } gop_control_statements(A) ::= gop_start_statement(B) gop_stop_statement(C).{ A = g_malloc(sizeof(gop_control_statement)); A->start = B; A->stop = C; A->extras = NULL; } gop_control_statements(A) ::= gop_start_statement(B).{ A = g_malloc(sizeof(gop_control_statement)); A->start = B; A->stop = NULL; A->extras = NULL; } gop_control_statements(A) ::= gop_stop_statement(C).{ A = g_malloc(sizeof(gop_control_statement)); A->start = NULL; A->stop = C; A->extras = NULL; } gop_control_statements(A) ::= extra_statement(D). { A = g_malloc(sizeof(gop_control_statement)); A->start = NULL; A->stop = NULL; A->extras = D; } gop_option_statements(A) ::= gop_timer_statements(B) gop_tree_statements(C). { A = g_malloc(sizeof(gop_control_statement)); A->timer_sts = B; A->tree_sts = C; } gop_option_statements(A) ::= gop_timer_statements(B). { A = g_malloc(sizeof(gop_timer_statement)); A->timer_sts = B; A->tree_sts = NULL; } gop_option_statements(A) ::= gop_tree_statements(C). { A = g_malloc(sizeof(gop_timer_statement)); A->tree_sts = C; A->timer_sts = NULL; } gop_timer_statements(A) ::= expiration_statement(B) idle_timeout_statement(C) lifetime_statement(D). { A = g_malloc(sizeof(gop_timer_statement)); A->expiration = B; A->idle_timeout = C; A->lifetime = D; } gop_timer_statements(A) ::= expiration_statement(B) idle_timeout_statement(C). { A = g_malloc(sizeof(gop_timer_statement)); A->expiration = B; A->idle_timeout = C; A->lifetime = mc->defaults.gop.lifetime; } gop_timer_statements(A) ::= expiration_statement(B) lifetime_statement(D). { A = g_malloc(sizeof(gop_timer_statement)); A->expiration = B; A->idle_timeout = mc->defaults.gop.lifetime; A->lifetime = D; } gop_timer_statements(A) ::= idle_timeout_statement(C) lifetime_statement(D). { A = g_malloc(sizeof(gop_timer_statement)); A->expiration = mc->defaults.gop.lifetime; A->idle_timeout = C; A->lifetime = D; } gop_timer_statements(A) ::= expiration_statement(B). { A = g_malloc(sizeof(gop_timer_statement)); A->expiration = B; A->idle_timeout = mc->defaults.gop.lifetime; A->lifetime = mc->defaults.gop.lifetime; } gop_timer_statements(A) ::= idle_timeout_statement(C). { A = g_malloc(sizeof(gop_timer_statement)); A->expiration = mc->defaults.gop.lifetime; A->idle_timeout = C; A->lifetime = mc->defaults.gop.lifetime; } gop_timer_statements(A) ::= lifetime_statement(D). { A = g_malloc(sizeof(gop_timer_statement)); A->expiration = mc->defaults.gop.lifetime; A->idle_timeout = mc->defaults.gop.lifetime; A->lifetime = D; } gop_tree_statements(A) ::= drop_unassigned_statement(B) show_goptree_statement(C) show_times_statement(D). { A = g_malloc(sizeof(gop_tree_statement)); A->drop_unassigned = B; A->pdu_tree_mode = C; A->show_times = D; } gop_tree_statements(A) ::= drop_unassigned_statement(B) show_goptree_statement(C). { A = g_malloc(sizeof(gop_tree_statement)); A->drop_unassigned = B; A->pdu_tree_mode = C; A->show_times = mc->defaults.gop.show_times; } gop_tree_statements(A) ::= drop_unassigned_statement(B) show_times_statement(D). { A = g_malloc(sizeof(gop_tree_statement)); A->drop_unassigned = B; A->pdu_tree_mode = mc->defaults.gop.pdu_tree_mode; A->show_times = D; } gop_tree_statements(A) ::= show_goptree_statement(C) show_times_statement(D). { A = g_malloc(sizeof(gop_tree_statement)); A->drop_unassigned = mc->defaults.gop.drop_unassigned; A->pdu_tree_mode = C; A->show_times = D; } gop_tree_statements(A) ::= drop_unassigned_statement(B). { A = g_malloc(sizeof(gop_tree_statement)); A->drop_unassigned = B; A->pdu_tree_mode = mc->defaults.gop.pdu_tree_mode; A->show_times = mc->defaults.gop.show_times; } gop_tree_statements(A) ::= show_goptree_statement(C). { A = g_malloc(sizeof(gop_tree_statement)); A->drop_unassigned = mc->defaults.gop.drop_unassigned; A->pdu_tree_mode = C; A->show_times = mc->defaults.gop.show_times; } gop_tree_statements(A) ::= show_times_statement(D). { A = g_malloc(sizeof(gop_tree_statement)); A->drop_unassigned = mc->defaults.gop.drop_unassigned; A->pdu_tree_mode = mc->defaults.gop.pdu_tree_mode; A->show_times = D; } gop_start_statement(A) ::= START_KW avpl(B) SEMICOLON. { A = B; } gop_stop_statement(A) ::= STOP_KW avpl(B) SEMICOLON. { A = B; } show_goptree_statement(A) ::= SHOW_TREE_KW gop_tree_mode(B) SEMICOLON. { A = B; } show_times_statement(A) ::= SHOW_TIMES_KW true_false(B) SEMICOLON. { A = B; } expiration_statement(A) ::= EXPIRATION_KW time_value(B) SEMICOLON. { A = B; } idle_timeout_statement(A) ::= IDLE_TIMEOUT_KW time_value(B) SEMICOLON. { A = B; } lifetime_statement(A) ::= LIFETIME_KW time_value(B) SEMICOLON. { A = B; } gop_tree_mode(A) ::= NO_TREE_KW. { A = GOP_NO_TREE; } gop_tree_mode(A) ::= PDU_TREE_KW. { A = GOP_PDU_TREE; } gop_tree_mode(A) ::= FRAME_TREE_KW. { A = GOP_FRAME_TREE; } gop_tree_mode(A) ::= BASIC_TREE_KW. { A = GOP_BASIC_PDU_TREE; } true_false(A) ::= TRUE_KW. { A = TRUE; } true_false(A) ::= FALSE_KW. { A = FALSE; } pdu_name(A) ::= NAME(B). { mate_cfg_pdu* c; if (( c = g_hash_table_lookup(mc->pducfgs,B) )) { A = c->name; } else { configuration_error(mc,"No such Pdu: '%s'",B); } } time_value(A) ::= FLOATING(B). { A = (float) strtod(B,NULL); } time_value(A) ::= INTEGER(B). { A = (float) strtod(B,NULL); } /************* GOG */ gog_decl ::= GOG_KW NAME(A) OPEN_BRACE gog_statements(B) CLOSE_BRACE SEMICOLON. { mate_cfg_gog* cfg = NULL; if ( g_hash_table_lookup(mc->gogcfgs,A) ) { configuration_error(mc,"Gog '%s' exists already ",A); } cfg = new_gogcfg(A); cfg->expiration = B->expiration; cfg->gop_tree_mode = B->gop_tree_mode; cfg->transforms = B->transform_list ? B->transform_list : g_ptr_array_new(); cfg->keys = B->current_gogkeys; if (B->extras) { merge_avpl(cfg->extra,B->extras,TRUE); delete_avpl(B->extras,TRUE); } g_free(B); } gog_statements(A) ::= expiration_statement(B) gog_goptree_statement(C) gog_key_statements(D) extra_statement(E) transform_list_statement(F). { A = g_malloc(sizeof(gog_statement_t)); A->expiration = B; A->gop_tree_mode = C; A->current_gogkeys = D; A->extras = E; A->transform_list = F; } gog_statements(A) ::= expiration_statement(B) gog_goptree_statement(C) gog_key_statements(D) transform_list_statement(F). { A = g_malloc(sizeof(gog_statement_t)); A->expiration = B; A->gop_tree_mode = C; A->current_gogkeys = D; A->extras = new_avpl(""); A->transform_list = F; } gog_statements(A) ::= expiration_statement(B) gog_key_statements(D) extra_statement(E) transform_list_statement(F). { A = g_malloc(sizeof(gog_statement_t)); A->expiration = B; A->gop_tree_mode = mc->defaults.gog.gop_tree_mode; A->current_gogkeys = D; A->extras = E; A->transform_list = F; } gog_statements(A) ::= expiration_statement(B) gog_key_statements(D) transform_list_statement(F). { A = g_malloc(sizeof(gog_statement_t)); A->expiration = B; A->gop_tree_mode = mc->defaults.gog.gop_tree_mode; A->current_gogkeys = D; A->extras = new_avpl(""); A->transform_list = F; } gog_statements(A) ::= gog_goptree_statement(C) gog_key_statements(D) extra_statement(E) transform_list_statement(F). { A = g_malloc(sizeof(gog_statement_t)); A->expiration = mc->defaults.gog.expiration; A->gop_tree_mode = C; A->current_gogkeys = D; A->extras = E; A->transform_list = F; } gog_statements(A) ::= gog_goptree_statement(C) gog_key_statements(D) transform_list_statement(F). { A = g_malloc(sizeof(gog_statement_t)); A->expiration = mc->defaults.gog.expiration; A->gop_tree_mode = C; A->current_gogkeys = D; A->extras = new_avpl(""); A->transform_list = F; } gog_statements(A) ::= gog_key_statements(D) extra_statement(E) transform_list_statement(F). { A = g_malloc(sizeof(gog_statement_t)); A->expiration = mc->defaults.gog.expiration; A->gop_tree_mode = mc->defaults.gog.gop_tree_mode; A->current_gogkeys = D; A->extras = E; A->transform_list = F; } gog_statements(A) ::= gog_key_statements(D) transform_list_statement(F). { A = g_malloc(sizeof(gog_statement_t)); A->expiration = mc->defaults.gog.expiration; A->gop_tree_mode = mc->defaults.gog.gop_tree_mode; A->current_gogkeys = D; A->extras = new_avpl(""); A->transform_list = F; } gog_statements(A) ::= expiration_statement(B) gog_goptree_statement(C) gog_key_statements(D) extra_statement(E). { A = g_malloc(sizeof(gog_statement_t)); A->expiration = B; A->gop_tree_mode = C; A->current_gogkeys = D; A->extras = E; A->transform_list = NULL; } gog_statements(A) ::= expiration_statement(B) gog_goptree_statement(C) gog_key_statements(D). { A = g_malloc(sizeof(gog_statement_t)); A->expiration = B; A->gop_tree_mode = C; A->current_gogkeys = D; A->extras = new_avpl(""); A->transform_list = NULL; } gog_statements(A) ::= expiration_statement(B) gog_key_statements(D) extra_statement(E). { A = g_malloc(sizeof(gog_statement_t)); A->expiration = B; A->gop_tree_mode = mc->defaults.gog.gop_tree_mode; A->current_gogkeys = D; A->extras = E; A->transform_list = NULL; } gog_statements(A) ::= expiration_statement(B) gog_key_statements(D). { A = g_malloc(sizeof(gog_statement_t)); A->expiration = B; A->gop_tree_mode = mc->defaults.gog.gop_tree_mode; A->current_gogkeys = D; A->extras = new_avpl(""); A->transform_list = NULL; } gog_statements(A) ::= gog_goptree_statement(C) gog_key_statements(D) extra_statement(E). { A = g_malloc(sizeof(gog_statement_t)); A->expiration = mc->defaults.gog.expiration; A->gop_tree_mode = C; A->current_gogkeys = D; A->extras = E; A->transform_list = NULL; } gog_statements(A) ::= gog_goptree_statement(C) gog_key_statements(D). { A = g_malloc(sizeof(gog_statement_t)); A->expiration = mc->defaults.gog.expiration; A->gop_tree_mode = C; A->current_gogkeys = D; A->extras = new_avpl(""); A->transform_list = NULL; } gog_statements(A) ::= gog_key_statements(D) extra_statement(E). { A = g_malloc(sizeof(gog_statement_t)); A->expiration = mc->defaults.gog.expiration; A->gop_tree_mode = mc->defaults.gog.gop_tree_mode; A->current_gogkeys = D; A->extras = E; A->transform_list = NULL; } gog_statements(A) ::= gog_key_statements(D). { A = g_malloc(sizeof(gog_statement_t)); A->expiration = mc->defaults.gog.expiration; A->gop_tree_mode = mc->defaults.gog.gop_tree_mode; A->current_gogkeys = D; A->extras = new_avpl(""); A->transform_list = NULL; } gog_goptree_statement(A) ::= GOP_TREE_KW gop_tree_type(B) SEMICOLON. { A = B; } gop_tree_type(A) ::= NULL_TREE. { A = GOP_NULL_TREE; } gop_tree_type(A) ::= FULL_TREE. { A = GOP_FULL_TREE; } gop_tree_type(A) ::= BASIC_TREE. { A = GOP_BASIC_TREE; } gog_key_statements(A) ::= gog_key_statements(B) gog_key_statement(C). { loal_append(B,C); A = B; } gog_key_statements(A) ::= gog_key_statement(B). { A = new_loal(""); loal_append(A,B); } gog_key_statement(A) ::= MEMBER_KW gop_name(B) avpl(C) SEMICOLON. { rename_avpl(C,B); A = C; } gop_name(A) ::= NAME(B). { mate_cfg_gop* c; if (( c = g_hash_table_lookup(mc->gopcfgs,B) )) { A = c->name; } else { configuration_error(mc,"No Gop called '%s' has been already declared",B); } } /******************************************** GENERAL */ extra_statement(A) ::= EXTRA_KW avpl(B) SEMICOLON. { A = B; } transform_list_statement(A) ::= TRANSFORM_KW transform_list(B) SEMICOLON. { A = B; } transform_list(A) ::= transform_list(B) COMMA transform(C). { A = B; g_ptr_array_add(B,C); } transform_list(A) ::= transform(B). { A = g_ptr_array_new(); g_ptr_array_add(A,B); } transform(A) ::= NAME(B). { AVPL_Transf* t; if (( t = g_hash_table_lookup(mc->transfs,B) )) { A = t; } else { configuration_error(mc,"There's no such Transformation: %s",B); } } avpl(A) ::= OPEN_PARENS avps(B) CLOSE_PARENS. { A = B; } avpl(A) ::= OPEN_PARENS CLOSE_PARENS. { A = new_avpl(""); } avps(A) ::= avps(B) COMMA avp(C). { A = B; if ( ! insert_avp(B,C) ) delete_avp(C); } avps(A) ::= avp(B). { A = new_avpl(""); if ( ! insert_avp(A,B) ) delete_avp(B); } avp(A) ::= NAME(B) AVP_OPERATOR(C) value(D). { A = new_avp(B,D,*C); } avp(A) ::= NAME(B). { A = new_avp(B,"",'?'); } avp(A) ::= NAME(B) OPEN_BRACE avp_oneoff(C) CLOSE_BRACE. { A = new_avp(B,C,'|'); } avp_oneoff(A) ::= avp_oneoff(B) PIPE value(C). { A = g_strdup_printf("%s|%s",B,C); } avp_oneoff(A) ::= value(B). { A = g_strdup(B); } value(A) ::= QUOTED(B). { A = g_strdup(B); } value(A) ::= NAME(B). { A = g_strdup(B); } value(A) ::= FLOATING(B). { A = g_strdup(B); } value(A) ::= INTEGER(B). { A = g_strdup(B); } value(A) ::= DOTED_IP(B). { A = g_strdup(B); } value(A) ::= COLONIZED(B). { A = recolonize(mc,B); }