[asterisk-commits] murf: branch murf/fast-ast r44761 - in /team/murf/fast-ast: include/asterisk/...

asterisk-commits at lists.digium.com asterisk-commits at lists.digium.com
Mon Oct 9 08:48:03 MST 2006


Author: murf
Date: Mon Oct  9 10:48:03 2006
New Revision: 44761

URL: http://svn.digium.com/view/asterisk?rev=44761&view=rev
Log:
Fleshed out the syntax tree for pattern names

Removed:
    team/murf/fast-ast/include/asterisk/trb.h
Modified:
    team/murf/fast-ast/main/pbx.c

Modified: team/murf/fast-ast/main/pbx.c
URL: http://svn.digium.com/view/asterisk/team/murf/fast-ast/main/pbx.c?rev=44761&r1=44760&r2=44761&view=diff
==============================================================================
--- team/murf/fast-ast/main/pbx.c (original)
+++ team/murf/fast-ast/main/pbx.c Mon Oct  9 10:48:03 2006
@@ -161,11 +161,30 @@
 	const char pattern[0];
 };
 
+/*! \brief match_char: forms a syntax tree for quick matching of extension patterns */
+struct match_char
+{
+	int is_pattern; /* the pattern started with '_' */
+	char *x;
+	int specificity; /* simply the strlen of x, or 10 for X, 9 for Z, and 8 for N; and '.' and '!' will add 11 ? */
+	struct match_char *alt_char;
+	struct match_char *next_char;
+	struct ast_exten *exten; /* attached to last char of a pattern for exten */
+};
+
+struct scoreboard  /* make sure all fields are 0 before calling new_find_extension */
+{
+	int total_specificity;
+	int total_length;
+	struct ast_exten *exten;
+};
+
 /*! \brief ast_context: An extension context */
 struct ast_context {
 	ast_mutex_t lock; 			/*!< A lock to prevent multiple threads from clobbering the context */
 	struct ast_exten *root;			/*!< The root of the list of extensions */
 	struct trb_table *root_tree;            /*!< The root of the list of extensions in threaded red-black tree form */
+	struct match_char *pattern_tree;        /*!< A tree to speed up extension pattern matching */
 	struct ast_context *next;		/*!< Link them together */
 	struct ast_include *includes;		/*!< Include other contexts */
 	struct ast_ignorepat *ignorepats;	/*!< Patterns for which to continue playing dialtone */
@@ -245,6 +264,10 @@
 static int trb_compare_extens(const void *trb_a, const void *trb_b, void *trb_param);
 static int trb_compare_exten_numbers(const void *trb_a, const void *trb_b, void *trb_param);
 static int trb_compare_exten_labels(const void *trb_a, const void *trb_b, void *trb_param);
+void new_find_extension(char *str, struct scoreboard *score, struct match_char *tree, int length, int spec);
+struct match_char *already_in_tree(struct match_char *current, char *pat);
+struct match_char *add_pattern_node(struct ast_context *con, struct match_char *current, char *pattern, int is_pattern);
+struct match_char *create_match_char_tree(struct ast_context *con);
 
 
 static int trb_compare_contexts(const void *trb_a, const void *trb_b, void *trb_param)
@@ -600,15 +623,6 @@
 {
 	free(p);
 }
-
-struct match_char
-{
-	char *x;
-	int specificity; /* simply the strlen of x, or 10 for X, 9 for Z, and 8 for N; and '.' and '!' will add 11 ? */
-	struct match_char *alt_char;
-	struct match_char *next_char;
-	struct ast_exten *exten_match; /* attached to last char of a pattern for exten */
-};
 
 /* form a tree that fully describes all the patterns in a context's extensions 
  * in this tree, a "node" consists of a series of match_char structs linked in a chain
@@ -660,19 +674,12 @@
  *
  * */
 
-struct scoreboard  /* make sure all fields are 0 before calling new_find_extension */
-{
-	int total_specificity;
-	int total_length;
-	struct ast_extension *exten;
-};
-
 /* you only really update the scoreboard, if the new score is BETTER than the 
  * one stored there. ignore it otherwise.
  */
 
 
-static void update_scoreboard(struct scoreboard *board, int length, int spec, struct ast_extension *exten)
+static void update_scoreboard(struct scoreboard *board, int length, int spec, struct ast_exten *exten)
 {
 	if (length > board->total_length) {
 		board->total_specificity = spec;
@@ -692,8 +699,8 @@
 	for (p=tree; p; p=p->alt_char)
 	{
 		if (p->x[0] == 'N' && p->x[1] == 0 && *str >= '2' && *str <= '9' ) {
-			if (p->next && *(str+1))
-				find_extension(str+1, score, p->next_char, length+1, spec+8);
+			if (p->next_char && *(str+1))
+				new_find_extension(str+1, score, p->next_char, length+1, spec+8);
 			else if (p->exten) {
 				update_scoreboard(score, length+1, spec+8, p->exten);
 				return;
@@ -701,8 +708,8 @@
 				return;
 			}
 		} else if (p->x[0] == 'Z' && p->x[1] == 0 && *str >= '1' && *str <= '9' ) {
-			if (p->next && *(str+1))
-				find_extension(str+1, score, p->next_char, length+1, spec+9);
+			if (p->next_char && *(str+1))
+				new_find_extension(str+1, score, p->next_char, length+1, spec+9);
 			else if (p->exten) {
 				update_scoreboard(score, length+1, spec+9, p->exten);
 				return;
@@ -710,8 +717,8 @@
 				return;
 			}
 		} else if (p->x[0] == 'X' && p->x[1] == 0 && *str >= '0' && *str <= '9' ) {
-			if (p->next && *(str+1))
-				find_extension(str+1, score, p->next_char, length+1, spec+10);
+			if (p->next_char && *(str+1))
+				new_find_extension(str+1, score, p->next_char, length+1, spec+10);
 			else if (p->exten) {
 				update_scoreboard(score, length+1, spec+10, p->exten);
 				return;
@@ -725,8 +732,8 @@
 			update_scoreboard(score, length+1, spec+11, p->exten);
 			return;
 		} else if (index(p->x, *str)) {
-			if (p->next && *(str+1))
-				find_extension(str+1, score, p->next_char, length+1, spec+p->specificity);
+			if (p->next_char && *(str+1))
+				new_find_extension(str+1, score, p->next_char, length+1, spec+p->specificity);
 			else if (p->exten) {
 				update_scoreboard(score, length+1, spec+p->specificity, p->exten);
 				return;
@@ -750,10 +757,112 @@
  * filled. It could be done as a finishing step after extensions.conf or .ael is
  * loaded, or it could be done when the first search is encountered. It should only
  * have to be done once, until the next unload or reload.
+ *
+ * I guess forming this pattern tree would be analogous to compiling a regex.
  */
 
-void create_match_char_tree(struct ast_context *con)
-{
+
+struct match_char *already_in_tree(struct match_char *current, char *pat)
+{
+	struct match_char *t;
+	if (!current)
+		return 0;
+	for (t=current; t; t=t->alt_char) {
+		if (strcmp(pat,t->x) == 0) /* uh, we may want to sort exploded [] contents to make matching easy */
+			return t;
+	}
+	return 0;
+}
+
+struct match_char *add_pattern_node(struct ast_context *con, struct match_char *current, char *pattern, int is_pattern)
+{
+	struct match_char *m = (struct match_char *)malloc(sizeof(struct match_char));
+	m->x = strdup(pattern);
+	m->is_pattern = is_pattern;
+	
+	if (!con->pattern_tree) {
+		con->pattern_tree = m;
+	} else {
+		if (current->next_char) {
+			m->alt_char = current->next_char->alt_char;
+			current->next_char = m;
+		} else {
+			current->next_char = m;
+		}
+	}
+	return m;
+}
+
+struct match_char *create_match_char_tree(struct ast_context *con)
+{
+	struct trb_traverser t1;
+	struct ast_exten *e1;
+	struct match_char *m1,*m2;
+	char buf[256];
+	int already;
+	
+	trb_t_init(&t1, con->root_tree);
+	while( (e1 = trb_t_next(&t1)) ) {
+		int pattern = 0;
+		char *s1 = e1->exten;
+		m1 = con->pattern_tree; /* each pattern starts over at the root of the pattern tree */
+		already = 1;
+
+		if ( *s1 == '_') {
+			pattern = 1;
+			s1++;
+		}
+		while( *s1 )
+		{
+			if (pattern && *s1 == '[' && *(s1-1) != '\\') {
+				char *s2 = buf;
+				while (*s1 != ']' && *(s1-1) != '\\' ) {
+					if (*s1 == '\\') {
+						if (*(s1+1) == ']') {
+							*s2++ = ']';
+							s1++;s1++;
+						} else if (*(s1+1) == '\\') {
+							*s2++ = '\\';
+							s1++;s1++;
+						} else if (*(s1+1) == '-') {
+							*s2++ = '-';
+							s1++; s1++;
+						} else if (*(s1+1) == '[') {
+							*s2++ = '[';
+							s1++; s1++;
+						}
+					} else if (*s1 == '-') { /* remember to add some error checking to all this! */
+						char s3 = *(s1-1);
+						char s4 = *(s1+1);
+						for (s3++; s3 <= s4; s3++) {
+							*s2++ = s3;
+						}
+						s1++; s1++;
+					} else {
+						*s2++ = *s1++;
+					}
+				}
+			} else {
+				if (*s1 == '\\') {
+					s1++;
+					buf[0] = *s1;
+				} else {
+					buf[0] = *s1;
+				}
+				buf[1] = 0;
+			}
+
+			if (already && (m2=already_in_tree(m1,buf))) {
+				m1 = m2->next_char; /* m1 points to the node to compare against */
+			} else {
+				already = 0;
+				m1 = add_pattern_node(con, m1, buf, pattern); /* m1 is the node just added */
+			}
+			s1++; /* advance to next char */
+		}
+		m1->exten =  e1; /* that last node should have an exten pointer */
+	}
+	return m1; /* return the last node inserted, so you can add the exten data */
 }
 
 /*
@@ -1057,11 +1166,26 @@
 	return extension_match_core(pattern, data, needmore);
 }
 
+struct fake_context /* this struct is purely for matching in the RB tree */
+{
+	ast_mutex_t lock; 			
+	struct ast_exten *root;		
+	struct trb_table *root_tree;            
+	struct match_char *pattern_tree;       
+	struct ast_context *next;	
+	struct ast_include *includes;		
+	struct ast_ignorepat *ignorepats;	
+	const char *registrar;	
+	AST_LIST_HEAD_NOLOCK(, ast_sw) alts;	
+	ast_mutex_t macrolock;		
+	char name[256];		
+};
+
 struct ast_context *ast_context_find(const char *name)
 {
 	struct ast_context *tmp = NULL;
-	struct ast_context item;
-	item->name = name;
+	struct fake_context item;
+	strncpy(item.name,name,256);
 	ast_mutex_lock(&conlock);
 	tmp = trb_find(contexts_tree,&item);
 #ifdef NOTNOW
@@ -1119,8 +1243,8 @@
 	struct ast_sw *sw;
 	struct ast_exten pattern;
 
-	pattern->label = label;
-	pattern->priority = priority;
+	pattern.label = label;
+	pattern.priority = priority;
 
 	/* Initialize status if appropriate */
 	if (q->stacklen == 0) {
@@ -1142,8 +1266,8 @@
 	if (bypass)	/* bypass means we only look there */
 		tmp = bypass;
 	else {	/* look in contexts */
-		struct ast_context item;
-		item->name = name;
+		struct fake_context item;
+		strncpy(item.name,context,256);
 		tmp = trb_find(contexts_tree,&item);
 #ifdef NOTNOW
 		tmp = NULL;
@@ -2757,8 +2881,8 @@
 static struct ast_context *find_context_locked(const char *context)
 {
 	struct ast_context *c = NULL;
-	struct ast_context item;
-	item->name = context;
+	struct fake_context item;
+	strncpy(item.name, context, 256);
 	ast_lock_contexts();
 	c = trb_find(contexts_tree,&item);
 #ifdef NOTNOW
@@ -2985,8 +3109,8 @@
 {
 	struct ast_context *c = NULL;
 	int ret = -1;
-	struct ast_context item;
-	item->name = context;
+	struct fake_context item;
+	strncpy(item.name,context,256);
 	ast_lock_contexts();
 	c = trb_find(contexts_tree,&item);
 	if (c)
@@ -3020,8 +3144,8 @@
 {
 	struct ast_context *c = NULL;
 	int ret = -1;
-	struct ast_context item;
-	item->name = context;
+	struct fake_context item;
+	strncpy(item.name, context, 256);
 
 	ast_lock_contexts();
 
@@ -4644,6 +4768,7 @@
 			trb_delete(con->root_tree, e->exten);
 			trb_insert(con->root_tree, tmp->exten);
 			con->root = tmp;
+		}
 		if (tmp->priority == PRIORITY_HINT)
 			ast_change_hint(e,tmp);
 		/* Destroy the old one */



More information about the asterisk-commits mailing list