Index: doc/rt_ereg.conf.sample
===================================================================
--- doc/rt_ereg.conf.sample	(revision 525)
+++ doc/rt_ereg.conf.sample	(revision 525)
@@ -0,0 +1,21 @@
+# This file contains information for configuring the rt_ereg extension.
+# To find how to have freeDiameter load this extension, please refer to the freeDiameter documentation.
+#
+# The rt_ereg extension allows creation of routing rules based on AVP value matching regular expressions.
+
+# First, one must indicate which AVP should be used for matching. 
+# At the moment, only AVP with OCTETSTRING types are valid.
+#  AVP = "User-Name";
+# This parameter is mandatory. There is no default value.
+
+# Then a list of rules follow. A rule has this format:
+#  "pattern" : "server" += score ;
+# Where:
+#  pattern is the quoted-string regex to match, 
+#  server is the next hop in the routing list that will receive the
+#  score, which can be positive or negative.
+# Example:
+#  "[[:digit:]]*" : "serverA.example.net" += -3 ;
+#    means that if the AVP value is only numeric, the ServerA will have its score decreased by 3 points.
+#    (reminder: the server with the peer with the highest score gets the message)
+# Note that all rules are tested for each message that contain the AVP, not only the first match.
Index: c/rt_un_number.conf.sample
===================================================================
--- doc/rt_un_number.conf.sample	(revision 515)
+++ 	(revision )
@@ -1,11 +1,0 @@
-# This file contains information for configuring the rt_un_number extension.
-# To find how to have freeDiameter load this extension, please refer to the freeDiameter documentation.
-#
-# The rt_un_number extension is a simple showcase of load-balancing routing with
-# freeDiameter. It routes the messages to different servers based on a numerical
-# value contained in the User-Name.
-
-# The format of this configuration file is very simple, just declare
-# the list of all servers you whish to load-balance between.
-# serv = "server1.identity" ;
-# serv = "server2.identity" ;
Index: extensions/rt_ereg/CMakeLists.txt
===================================================================
--- extensions/rt_ereg/CMakeLists.txt	(revision 525)
+++ extensions/rt_ereg/CMakeLists.txt	(revision 525)
@@ -0,0 +1,44 @@
+# The rt_ereg extension
+PROJECT("Regular expression matching based routing extension" C)
+
+# Check if REG_STARTEND is provided on the host
+SET(CHECK_REG_STARTEND_SOURCE_CODE "
+	#include <unistd.h>
+	#include <regex.h>
+	int main() {
+	   return regexec(NULL, NULL, 0, NULL, REG_STARTEND);
+	}
+	")
+CHECK_C_SOURCE_COMPILES("${CHECK_REG_STARTEND_SOURCE_CODE}" HAVE_REG_STARTEND)
+IF (HAVE_REG_STARTEND)
+     ADD_DEFINITIONS(-DHAVE_REG_STARTEND)
+ENDIF (HAVE_REG_STARTEND)
+
+
+# Parser files
+BISON_FILE(rtereg_conf.y)
+FLEX_FILE(rtereg_conf.l)
+SET_SOURCE_FILES_PROPERTIES(lex.rtereg_conf.c rtereg_conf.tab.c PROPERTIES COMPILE_FLAGS "-I ${CMAKE_CURRENT_SOURCE_DIR}")
+
+# List of source files
+SET( RTEREG_SRC
+	rtereg.c
+	rtereg.h
+	lex.rtereg_conf.c
+	rtereg_conf.tab.c
+	rtereg_conf.tab.h
+)
+
+INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR})
+
+# Compile these files as a freeDiameter extension
+FD_ADD_EXTENSION(rt_ereg ${RTEREG_SRC})
+
+
+####
+## INSTALL section ##
+
+# We install with the daemon component because it is a base feature.
+INSTALL(TARGETS rt_ereg
+	LIBRARY DESTINATION ${INSTALL_EXTENSIONS_SUFFIX}
+	COMPONENT freeDiameter-daemon)
Index: extensions/rt_ereg/rtereg.c
===================================================================
--- extensions/rt_ereg/rtereg.c	(revision 525)
+++ extensions/rt_ereg/rtereg.c	(revision 525)
@@ -0,0 +1,222 @@
+/*********************************************************************************************************
+* Software License Agreement (BSD License)                                                               *
+* Author: Sebastien Decugis <sdecugis@nict.go.jp>							 *
+*													 *
+* Copyright (c) 2010, WIDE Project and NICT								 *
+* All rights reserved.											 *
+* 													 *
+* Redistribution and use of this software in source and binary forms, with or without modification, are  *
+* permitted provided that the following conditions are met:						 *
+* 													 *
+* * Redistributions of source code must retain the above 						 *
+*   copyright notice, this list of conditions and the 							 *
+*   following disclaimer.										 *
+*    													 *
+* * Redistributions in binary form must reproduce the above 						 *
+*   copyright notice, this list of conditions and the 							 *
+*   following disclaimer in the documentation and/or other						 *
+*   materials provided with the distribution.								 *
+* 													 *
+* * Neither the name of the WIDE Project or NICT nor the 						 *
+*   names of its contributors may be used to endorse or 						 *
+*   promote products derived from this software without 						 *
+*   specific prior written permission of WIDE Project and 						 *
+*   NICT.												 *
+* 													 *
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED *
+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
+* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR *
+* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 	 *
+* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 	 *
+* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR *
+* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF   *
+* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.								 *
+*********************************************************************************************************/
+
+/* 
+ * This extension allows to perform some pattern-matching on an AVP
+ * and send the message to a server accordingly.
+ * See rt_ereg.conf.sample file for the format of the configuration file.
+ */
+
+#include "rtereg.h"
+
+/* The configuration structure */
+struct rtereg_conf rtereg_conf;
+
+#ifndef HAVE_REG_STARTEND
+static char * buf = NULL;
+static size_t bufsz;
+static pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
+#endif /* HAVE_REG_STARTEND */
+
+static int proceed(char * value, size_t len, struct fd_list * candidates)
+{
+	int i;
+	
+	for (i = 0; i < rtereg_conf.rules_nb; i++) {
+		/* Does this pattern match the value? */
+		struct rtereg_rule * r = &rtereg_conf.rules[i];
+		int err = 0;
+		struct fd_list * c;
+		
+		#ifdef HAVE_REG_STARTEND
+		{
+			regmatch_t pmatch[1];
+			memset(pmatch, 0, sizeof(pmatch));
+			pmatch[0].rm_so = 0;
+			pmatch[0].rm_eo = len;
+			err = regexec(&r->preg, value, 0, pmatch, REG_STARTEND);
+		}
+		#else /* HAVE_REG_STARTEND */
+		{
+			/* We have a 0-terminated string */
+			err = regexec(&r->preg, value, 0, NULL, 0);
+		}
+		#endif /* HAVE_REG_STARTEND */
+		
+		if (err == REG_NOMATCH)
+			continue;
+			
+		if (err != 0) {
+			char * errstr;
+			size_t bl;
+
+			/* Error while compiling the regex */
+			TRACE_DEBUG(INFO, "Error while executing the regular expression '%s':", r->pattern);
+
+			/* Get the error message size */
+			bl = regerror(err, &r->preg, NULL, 0);
+
+			/* Alloc the buffer for error message */
+			CHECK_MALLOC( errstr = malloc(bl) );
+
+			/* Get the error message content */
+			regerror(err, &r->preg, errstr, bl);
+			TRACE_DEBUG(INFO, "\t%s", errstr);
+
+			/* Free the buffer, return the error */
+			free(errstr);
+			
+			return (err == REG_ESPACE) ? ENOMEM : EINVAL;
+		}
+		
+		/* From this point, the expression matched the AVP value */
+		TRACE_DEBUG(FULL, "[rt_ereg] Match: '%s' to value '%.*s' => '%s' += %d",
+					r->pattern,
+					len,
+					value,
+					r->server,
+					r->score);
+		
+		for (c = candidates->next; c != candidates; c = c->next) {
+			struct rtd_candidate * cand = (struct rtd_candidate *)c;
+
+			if (strcmp(r->server, cand->diamid) == 0) {
+				cand->score += r->score;
+				break;
+			}
+		}
+	};
+	
+	return 0;
+}
+
+/* The callback called on new messages */
+static int rtereg_out(void * cbdata, struct msg * msg, struct fd_list * candidates)
+{
+	struct avp * avp = NULL;
+	
+	TRACE_ENTRY("%p %p %p", cbdata, msg, candidates);
+	
+	CHECK_PARAMS(msg && candidates);
+	
+	/* Check if it is worth processing the message */
+	if (FD_IS_LIST_EMPTY(candidates)) {
+		return 0;
+	}
+	
+	/* Now search the AVP in the message */
+	CHECK_FCT( fd_msg_search_avp ( msg, rtereg_conf.avp, &avp ) );
+	if (avp != NULL) {
+		struct avp_hdr * ahdr = NULL;
+		CHECK_FCT( fd_msg_avp_hdr ( avp, &ahdr ) );
+		if (ahdr->avp_value != NULL) {
+			int ret;
+		
+#ifndef HAVE_REG_STARTEND
+			/* Lock the buffer */
+			CHECK_POSIX( pthread_mutex_lock(&mtx) );
+			
+			/* Augment the buffer if needed */
+			if (ahdr->avp_value->os.len >= bufsz) {
+				CHECK_MALLOC_DO( buf = realloc(buf, ahdr->avp_value->os.len + 1), 
+					{ pthread_mutex_unlock(&mtx); return ENOMEM; } );
+			}
+			
+			/* Copy the AVP value */
+			memcpy(buf, ahdr->avp_value->os.data, ahdr->avp_value->os.len);
+			buf[ahdr->avp_value->os.len] = '\0';
+			
+			/* Now apply the rules */
+			ret = proceed(buf, ahdr->avp_value->os.len, candidates);
+			
+			CHECK_POSIX(pthread_mutex_unlock(&mtx));
+			
+			CHECK_FCT(ret);
+#else /* HAVE_REG_STARTEND */
+			CHECK_FCT( proceed(ahdr->avp_value->os.data, ahdr->avp_value->os.len, candidates) );
+#endif /* HAVE_REG_STARTEND */
+		}
+	}
+	
+	return 0;
+}
+
+/* handler */
+static struct fd_rt_out_hdl * rtereg_hdl = NULL;
+
+/* entry point */
+static int rtereg_entry(char * conffile)
+{
+	TRACE_ENTRY("%p", conffile);
+	
+	/* Initialize the configuration */
+	memset(&rtereg_conf, 0, sizeof(rtereg_conf));
+	
+	/* Parse the configuration file */
+	CHECK_FCT( rtereg_conf_handle(conffile) );
+	
+	/* Register the callback */
+	CHECK_FCT( fd_rt_out_register( rtereg_out, NULL, 1, &rtereg_hdl ) );
+	
+	/* We're done */
+	return 0;
+}
+
+/* Unload */
+void fd_ext_fini(void)
+{
+	int i;
+	TRACE_ENTRY();
+	
+	/* Unregister the cb */
+	CHECK_FCT_DO( fd_rt_out_unregister ( rtereg_hdl, NULL ), /* continue */ );
+	
+	/* Destroy the data */
+	if (rtereg_conf.rules) 
+		for (i = 0; i < rtereg_conf.rules_nb; i++) {
+			free(rtereg_conf.rules[i].pattern);
+			free(rtereg_conf.rules[i].server);
+			regfree(&rtereg_conf.rules[i].preg);
+		}
+	free(rtereg_conf.rules);
+#ifndef HAVE_REG_STARTEND
+	free(buf);
+#endif /* HAVE_REG_STARTEND */
+	
+	/* Done */
+	return ;
+}
+
+EXTENSION_ENTRY("rt_ereg", rtereg_entry);
Index: extensions/rt_ereg/rtereg.h
===================================================================
--- extensions/rt_ereg/rtereg.h	(revision 525)
+++ extensions/rt_ereg/rtereg.h	(revision 525)
@@ -0,0 +1,64 @@
+/*********************************************************************************************************
+* Software License Agreement (BSD License)                                                               *
+* Author: Sebastien Decugis <sdecugis@nict.go.jp>							 *
+*													 *
+* Copyright (c) 2010, WIDE Project and NICT								 *
+* All rights reserved.											 *
+* 													 *
+* Redistribution and use of this software in source and binary forms, with or without modification, are  *
+* permitted provided that the following conditions are met:						 *
+* 													 *
+* * Redistributions of source code must retain the above 						 *
+*   copyright notice, this list of conditions and the 							 *
+*   following disclaimer.										 *
+*    													 *
+* * Redistributions in binary form must reproduce the above 						 *
+*   copyright notice, this list of conditions and the 							 *
+*   following disclaimer in the documentation and/or other						 *
+*   materials provided with the distribution.								 *
+* 													 *
+* * Neither the name of the WIDE Project or NICT nor the 						 *
+*   names of its contributors may be used to endorse or 						 *
+*   promote products derived from this software without 						 *
+*   specific prior written permission of WIDE Project and 						 *
+*   NICT.												 *
+* 													 *
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED *
+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
+* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR *
+* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 	 *
+* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 	 *
+* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR *
+* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF   *
+* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.								 *
+*********************************************************************************************************/
+
+/*
+ *  See the rt_ereg.conf.sample file for the format of the configuration file.
+ */
+ 
+/* FreeDiameter's common include file */
+#include <freeDiameter/extension.h>
+#include <regex.h>
+
+
+/* Parse the configuration file */
+int rtereg_conf_handle(char * conffile);
+
+struct rtereg_rule {
+	char *  pattern; /* The pattern we try to match the AVP value to */
+	regex_t preg;    /* compiled regex */
+	char *  server;  /* The peer that gets its score raised in case of match */
+	int     score;   /* The relative value that is added to the peer's score */
+};
+	
+
+/* The configuration structure */
+extern struct rtereg_conf {
+	int			rules_nb; /* Number of rules in the configuration */
+	struct rtereg_rule 	*rules;   /* The array of rules */
+	
+	struct dict_object * avp; /* cache the dictionary object that we are searching */
+	
+} rtereg_conf;
+
Index: extensions/rt_ereg/rtereg_conf.l
===================================================================
--- extensions/rt_ereg/rtereg_conf.l	(revision 525)
+++ extensions/rt_ereg/rtereg_conf.l	(revision 525)
@@ -0,0 +1,119 @@
+/*********************************************************************************************************
+* Software License Agreement (BSD License)                                                               *
+* Author: Sebastien Decugis <sdecugis@nict.go.jp>							 *
+*													 *
+* Copyright (c) 2010, WIDE Project and NICT								 *
+* All rights reserved.											 *
+* 													 *
+* Redistribution and use of this software in source and binary forms, with or without modification, are  *
+* permitted provided that the following conditions are met:						 *
+* 													 *
+* * Redistributions of source code must retain the above 						 *
+*   copyright notice, this list of conditions and the 							 *
+*   following disclaimer.										 *
+*    													 *
+* * Redistributions in binary form must reproduce the above 						 *
+*   copyright notice, this list of conditions and the 							 *
+*   following disclaimer in the documentation and/or other						 *
+*   materials provided with the distribution.								 *
+* 													 *
+* * Neither the name of the WIDE Project or NICT nor the 						 *
+*   names of its contributors may be used to endorse or 						 *
+*   promote products derived from this software without 						 *
+*   specific prior written permission of WIDE Project and 						 *
+*   NICT.												 *
+* 													 *
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED *
+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
+* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR *
+* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 	 *
+* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 	 *
+* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR *
+* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF   *
+* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.								 *
+*********************************************************************************************************/
+
+/* Tokenizer
+ *
+ */
+
+%{
+#include "rtereg.h"
+/* Include yacc tokens definitions */
+#include "rtereg_conf.tab.h"
+
+/* Update the column information */
+#define YY_USER_ACTION { 						\
+	yylloc->first_column = yylloc->last_column + 1; 		\
+	yylloc->last_column = yylloc->first_column + yyleng - 1;	\
+}
+
+/* Avoid warning with newer flex */
+#define YY_NO_INPUT
+
+%}
+
+qstring		\"[^\"\n]*\"
+
+
+%option bison-bridge bison-locations
+%option noyywrap
+%option nounput
+
+%%
+
+	/* Update the line count */
+\n			{
+				yylloc->first_line++; 
+				yylloc->last_line++; 
+				yylloc->last_column=0; 
+			}
+	 
+	/* Eat all spaces but not new lines */
+([[:space:]]{-}[\n])+	;
+	/* Eat all comments */
+#.*$			;
+
+
+	/* Recognize quoted strings */
+{qstring}		{
+				/* Match a quoted string. */
+				CHECK_MALLOC_DO( yylval->string = strdup(yytext+1), 
+				{
+					TRACE_DEBUG(INFO, "Unable to copy the string '%s': %s\n", yytext, strerror(errno));
+					return LEX_ERROR; /* trig an error in yacc parser */
+				} );
+				yylval->string[strlen(yytext) - 2] = '\0';
+				return QSTRING;
+			}
+	
+
+	/* Recognize any integer */
+[-]?[[:digit:]]+	{
+				/* Convert this to an integer value */
+				int ret=0;
+				ret = sscanf(yytext, "%i", &yylval->integer);
+				if (ret != 1) {
+					/* No matching: an error occurred */
+					fd_log_debug("Unable to convert the value '%s' to a valid number: %s\n", yytext, strerror(errno));
+					return LEX_ERROR; /* trig an error in yacc parser */
+					/* Maybe we could REJECT instead of failing here? */
+				}
+				return INTEGER;
+			}
+			
+	
+	
+	/* The key words */	
+(?i:"AVP")	 	{	return AVP;	}
+			
+	/* Valid single characters for yyparse */
+[=:;+-]			{ return yytext[0]; }
+
+	/* Unrecognized sequence, if it did not match any previous pattern */
+[^[:space:]\":=+;\n]+	{ 
+				fd_log_debug("Unrecognized text on line %d col %d: '%s'.\n", yylloc->first_line, yylloc->first_column, yytext);
+			 	return LEX_ERROR; 
+			}
+
+%%
Index: extensions/rt_ereg/rtereg_conf.y
===================================================================
--- extensions/rt_ereg/rtereg_conf.y	(revision 525)
+++ extensions/rt_ereg/rtereg_conf.y	(revision 525)
@@ -0,0 +1,209 @@
+/*********************************************************************************************************
+* Software License Agreement (BSD License)                                                               *
+* Author: Sebastien Decugis <sdecugis@nict.go.jp>							 *
+*													 *
+* Copyright (c) 2010, WIDE Project and NICT								 *
+* All rights reserved.											 *
+* 													 *
+* Redistribution and use of this software in source and binary forms, with or without modification, are  *
+* permitted provided that the following conditions are met:						 *
+* 													 *
+* * Redistributions of source code must retain the above 						 *
+*   copyright notice, this list of conditions and the 							 *
+*   following disclaimer.										 *
+*    													 *
+* * Redistributions in binary form must reproduce the above 						 *
+*   copyright notice, this list of conditions and the 							 *
+*   following disclaimer in the documentation and/or other						 *
+*   materials provided with the distribution.								 *
+* 													 *
+* * Neither the name of the WIDE Project or NICT nor the 						 *
+*   names of its contributors may be used to endorse or 						 *
+*   promote products derived from this software without 						 *
+*   specific prior written permission of WIDE Project and 						 *
+*   NICT.												 *
+* 													 *
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED *
+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
+* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR *
+* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 	 *
+* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 	 *
+* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR *
+* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF   *
+* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.								 *
+*********************************************************************************************************/
+
+/* Yacc extension's configuration parser.
+ */
+
+/* For development only : */
+%debug 
+%error-verbose
+
+/* The parser receives the configuration file filename as parameter */
+%parse-param {char * conffile}
+
+/* Keep track of location */
+%locations 
+%pure-parser
+
+%{
+#include "rtereg.h"
+#include "rtereg_conf.tab.h"	/* bison is not smart enough to define the YYLTYPE before including this code, so... */
+
+/* Forward declaration */
+int yyparse(char * conffile);
+
+/* Parse the configuration file */
+int rtereg_conf_handle(char * conffile)
+{
+	extern FILE * rtereg_confin;
+	int ret;
+	
+	TRACE_ENTRY("%p", conffile);
+	
+	TRACE_DEBUG (FULL, "Parsing configuration file: %s...", conffile);
+	
+	rtereg_confin = fopen(conffile, "r");
+	if (rtereg_confin == NULL) {
+		ret = errno;
+		fd_log_debug("Unable to open extension configuration file %s for reading: %s\n", conffile, strerror(ret));
+		TRACE_DEBUG (INFO, "Error occurred, message logged -- configuration file.");
+		return ret;
+	}
+
+	ret = yyparse(conffile);
+
+	fclose(rtereg_confin);
+
+	if (ret != 0) {
+		TRACE_DEBUG (INFO, "Unable to parse the configuration file.");
+		return EINVAL;
+	} else {
+		TRACE_DEBUG(FULL, "[rt-ereg] Added %d rules successfully.", rtereg_conf.rules_nb);
+	}
+	
+	return 0;
+}
+
+/* The Lex parser prototype */
+int rtereg_conflex(YYSTYPE *lvalp, YYLTYPE *llocp);
+
+/* Function to report the errors */
+void yyerror (YYLTYPE *ploc, char * conffile, char const *s)
+{
+	TRACE_DEBUG(INFO, "Error in configuration parsing");
+	
+	if (ploc->first_line != ploc->last_line)
+		fd_log_debug("%s:%d.%d-%d.%d : %s\n", conffile, ploc->first_line, ploc->first_column, ploc->last_line, ploc->last_column, s);
+	else if (ploc->first_column != ploc->last_column)
+		fd_log_debug("%s:%d.%d-%d : %s\n", conffile, ploc->first_line, ploc->first_column, ploc->last_column, s);
+	else
+		fd_log_debug("%s:%d.%d : %s\n", conffile, ploc->first_line, ploc->first_column, s);
+}
+
+%}
+
+/* Values returned by lex for token */
+%union {
+	char 		*string;	/* The string is allocated by strdup in lex.*/
+	int		integer;
+}
+
+/* In case of error in the lexical analysis */
+%token 		LEX_ERROR
+
+/* A (de)quoted string (malloc'd in lex parser; it must be freed after use) */
+%token <string>	 QSTRING
+%token <integer> INTEGER
+
+/* Tokens */
+%token 		AVP
+
+
+/* -------------------------------------- */
+%%
+
+	/* The grammar definition */
+conffile:		rules avp rules
+			;
+			
+	/* a server entry */
+avp:			AVP '=' QSTRING ';'
+			{
+				if (rtereg_conf.avp != NULL) {
+					yyerror(&yylloc, conffile, "Only one AVP can be specified");
+					YYERROR;
+				}
+				
+				CHECK_FCT_DO( fd_dict_search ( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, $3, &rtereg_conf.avp, ENOENT ),
+					{
+						TRACE_DEBUG(INFO, "Unable to find '%s' AVP in the loaded dictionaries.", $3);
+						yyerror (&yylloc, conffile, "Invalid AVP value.");
+						YYERROR;
+					} );
+				
+				/* Now check the type */
+				{
+					struct dict_avp_data data;
+					CHECK_FCT( fd_dict_getval( rtereg_conf.avp, &data) );
+					CHECK_PARAMS_DO (data.avp_basetype == AVP_TYPE_OCTETSTRING, 
+						{
+							TRACE_DEBUG(INFO, "'%s' AVP in not an OCTETSTRING AVP (%d).", $3, data.avp_basetype);
+							yyerror (&yylloc, conffile, "AVP in not an OCTETSTRING type.");
+							YYERROR;
+						} );
+				}
+			}
+			;
+			
+rules:			/* empty OK */
+			| rules rule
+			;
+			
+rule:			QSTRING ':' QSTRING '+' '=' INTEGER ';'
+			{
+				struct rtereg_rule * new;
+				int err;
+				
+				/* Add new rule in the array */
+				rtereg_conf.rules_nb += 1;
+				CHECK_MALLOC_DO(rtereg_conf.rules = realloc(rtereg_conf.rules, rtereg_conf.rules_nb * sizeof(struct rtereg_rule)),
+					{
+						yyerror (&yylloc, conffile, "Not enough memory to store the configuration...");
+						YYERROR;
+					} );
+				
+				new = &rtereg_conf.rules[rtereg_conf.rules_nb - 1];
+				
+				new->pattern = $1;
+				new->server  = $3;
+				new->score   = $6;
+				
+				/* Attempt to compile the regex */
+				CHECK_FCT_DO( err=regcomp(&new->preg, new->pattern, REG_EXTENDED | REG_NOSUB),
+					{
+						char * buf;
+						size_t bl;
+
+						/* Error while compiling the regex */
+						TRACE_DEBUG(INFO, "Error while compiling the regular expression '%s':", new->pattern);
+
+						/* Get the error message size */
+						bl = regerror(err, &new->preg, NULL, 0);
+
+						/* Alloc the buffer for error message */
+						CHECK_MALLOC( buf = malloc(bl) );
+
+						/* Get the error message content */
+						regerror(err, &new->preg, buf, bl);
+						TRACE_DEBUG(INFO, "\t%s", buf);
+						
+						/* Free the buffer, return the error */
+						free(buf);
+						
+						yyerror (&yylloc, conffile, "Invalid regular expression.");
+						YYERROR;
+					} );
+			}
+			;
