[Asterisk-Dev] better pattern matcher

Reini Urban r.urban at inode.at
Tue Jun 10 08:48:54 MST 2003


Reini Urban wrote:
> This is my matcher. Most code is in public domain.

And attached is the patch to pbx.c to be applied to CVS.

>> well, for the beginning I added support to continue to match after a "."
>> to be able to add extensions after the dialed number and not only 
>> before. :)
>>
>> e.g "_0N.8500" matches my voicemail extension for all dialed numbers.
>>
>> I'll commit this short patch on Tuesday, because I have to do more 
>> testing and the weekend is free.
-- 
Reini Urban - Entwicklung - http://inode.at
-------------- next part --------------
Index: pbx.c
===================================================================
RCS file: /usr/cvsroot/asterisk/pbx.c,v
retrieving revision 1.21
diff -u -b -b -u -r1.21 pbx.c
--- pbx.c	22 May 2003 04:38:46 -0000	1.21
+++ pbx.c	10 Jun 2003 16:04:59 -0000
@@ -148,6 +148,7 @@
     struct ast_hint *next;
 };
 
+int ast_extension_patmatch(const char *pattern, const char *data);
 
 static int pbx_builtin_prefix(struct ast_channel *, void *);
 static int pbx_builtin_suffix(struct ast_channel *, void *);
@@ -558,16 +559,100 @@
 	}\
 }
 
+/* derived from code by Steffen Offermann 1991 (public domain)
+   http://www.cs.umu.se/~isak/Snippets/xstrcmp.c
+*/
+int ast_extension_patmatch(const char *pattern, const char *data) 
+{
+    ast_log(LOG_DEBUG, " >>> %s =~ /%s/\n", data, pattern);
+    switch (toupper(*pattern))
+	{
+	case '\0':
+	    ast_log(LOG_DEBUG, " !>>> %s => %s\n", data, !*data ? "OK" : "FAIL");
+	    return !*data;
+	    
+	case ' ':
+	case '-':
+	    /* Ignore these characters in the pattern */
+	    return *data && ast_extension_patmatch(pattern+1, data);
+
+	case '.' : /* wildcard */
+	    if (! *(pattern+1) ) 
+		return *data;
+	    else
+		return ast_extension_patmatch(pattern+1, data) || (*data && ast_extension_patmatch(pattern, data+1));
+
+/*	    
+	case '?' :
+	    return *data && ast_extension_patmatch(pattern+1, data+1);
+*/	    
+	case 'X':
+	    return ((*data >= '0') && (*data <= '9')) && ast_extension_patmatch(pattern+1, data+1);
+	    
+	case 'Z':
+	    return ((*data >= '1') && (*data <= '9')) && ast_extension_patmatch(pattern+1, data+1);
+	    
+	case 'N':
+	    return ((*data >= '2') && (*data <= '9')) && ast_extension_patmatch(pattern+1, data+1);
+	    
+	case '[':
+	    /* Begin Mark Spencer CODE */
+	    {
+		int i,border=0;
+		char *where;
+		pattern++;
+		where=strchr(pattern,']');
+		if (where)
+		    border=(int)(where-pattern);
+		if (!where || border > strlen(pattern)) {
+		    ast_log(LOG_WARNING, "Wrong [%s] pattern usage\n", pattern);
+		    return 0;
+		}
+		for (i=0; i<border; i++) {
+		    if (i+2<border) {
+			if (*data==pattern[i])
+			    return 1;
+		        else if (pattern[i+1]=='-') {
+			    if (*data >= pattern[i] && *data <= pattern[i+2]) {
+				return ast_extension_patmatch(where+1, data+1);
+			    } else {
+				i+=2;
+				continue;
+			    }
+			}
+		    }
+		}
+		pattern+=border;
+		break;
+	    }
+	    /* End Mark Spencer CODE */
+	    
+	default  :
+	    return (toupper(*pattern) == toupper(*data)) && ast_extension_patmatch(pattern+1, data+1);
+	}
+    return 0;
+}
+
 int ast_extension_match(char *pattern, char *data)
 {
 	int match;
-	/* If they're the same return */
-	if (!strcmp(pattern, data))
-		return 1;
-	EXTENSION_MATCH_CORE(data,pattern,match);
-	/* Must be at the end of both */
-	if (*data || (*pattern && (*pattern != '/')))
-		match = 0;
+	if (!*pattern) {
+	    ast_log(LOG_WARNING, "ast_extension_match: empty pattern\n");
+	    return 0;
+	}
+	if (!*data) {
+	    ast_log(LOG_WARNING, "ast_extension_match: empty data\n");
+	    return 0;
+	}
+	if (pattern[0] != '_') {
+	    match = (strcmp(pattern, data) == 0);
+	    ast_log(LOG_DEBUG, "ast_extension_match %s == /%s/", data, pattern);
+	    return (strcmp(pattern, data) == 0);
+	} else {
+	    ast_log(LOG_DEBUG, "ast_extension_match %s =~ /%s/", data, pattern);
+	    match = ast_extension_patmatch(data,pattern+1);
+	}
+	ast_log(LOG_DEBUG, " => %d\n", match);
 	return match;
 }
 
@@ -583,7 +668,9 @@
 		(!needmore || (strlen(pattern) > strlen(data)))) {
 		return 1;
 	}
-	EXTENSION_MATCH_CORE(data,pattern,match);
+	if (pattern[0] == '_') {
+	    match = ast_extension_patmatch(data,pattern+1);
+	}
 	/* If there's more or we don't care about more, return non-zero, otlherwise it's a miss */
 	if (!needmore || *pattern) {
 		return match;


More information about the asterisk-dev mailing list