[asterisk-dev] [PATCH] Sort patterns for termination
Jan Engelhardt
jengelh at computergmbh.de
Tue Jul 3 17:15:21 CDT 2007
Hi,
there's a case with the use of pbx_realtime.so where multiple patterns
(_0. and _0174. here) can match a call like "017412345678".
In this case, it is preferable to match with _0174. instead of _0.
mysql> SELECT * FROM config_extensions WHERE
context="TERMINATION" order by exten;
+------+-------------+--------+----------+------------+-
| id | context | exten | priority | app | ...
+------+-------------+--------+----------+------------+-
| 7502 | TERMINATION | _0. | 3 | Congestion | ...
| 7501 | TERMINATION | _0. | 2 | Busy |
| 7500 | TERMINATION | _0. | 1 | Dial | ...
| 7505 | TERMINATION | _0174. | 3 | Congestion |
| 7504 | TERMINATION | _0174. | 2 | Busy | ...
| 7503 | TERMINATION | _0174. | 1 | Dial |
+------+-------------+--------+----------+------------+-
To actually do this, the patterns need to be sorted, which the patch below
does.
This is a follow-up to http://bugs.digium.com/view.php?id=10109
(- I am not either interested in signing up for yet another account.)[1]
Jan
--
[1] https://lists.linux-foundation.org/pipermail/desktop_architects/2007-February/001129.html
diff -dpru asterisk-1.2.19~/config.c asterisk-1.2.19/config.c
--- asterisk-1.2.19~/config.c 2007-06-15 01:21:45.000000000 +0200
+++ asterisk-1.2.19/config.c 2007-07-03 22:23:04.207821000 +0200
@@ -24,6 +24,7 @@
* See README.realtime
*/
+#include <ctype.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
@@ -96,6 +97,124 @@ struct ast_config {
int max_include_level;
};
+static int ast_regex_compare(const void *pa, const void *pb)
+{
+ const struct ast_category *const *qa = pa;
+ const struct ast_category *const *qb = pb;
+ const char *a = (*qa)->name;
+ const char *b = (*qb)->name;
+
+ /* Ruleset: long non-regex < short non-regex < regex */
+ if (*a != '_' && *b != '_')
+ return strlen(b) - strlen(a);
+ if (*a != '_' && *b == '_')
+ return -1;
+ if (*a == '_' && *b != '_')
+ return 1;
+
+ ++a;
+ ++b;
+
+ /* Ruleset: digit < '[' <= '.' < '\0' */
+ while (*a != '\0' && *b != '\0') {
+ if (isdigit(*a)) {
+ switch (*b) {
+ case '[': return -1;
+ case '.': return -1;
+ case '\0': return -1;
+ }
+ } else if (*a == '[') {
+ if (isdigit(*b)) {
+ return 1;
+ } else if (*b == '[') {
+ a = strchr(a, ']');
+ b = strchr(b, ']');
+ if (a == NULL || b == NULL) {
+ ast_log(LOG_DEBUG, "Invalid regex\n");
+ return 0;
+ }
+ --a;
+ --b;
+ } else if (*b == '.') {
+ a = strchr(a, ']');
+ if (a == NULL) {
+ ast_log(LOG_DEBUG, "Invalid regex\n");
+ return 0;
+ }
+ --a;
+ } else if (*b == '\0') {
+ return -1;
+ }
+ } else if (*a == '.') {
+ if (isdigit(*b)) {
+ return 1;
+ } else if (*b == '[') {
+ b = strchr(b, ']');
+ if (b == NULL) {
+ ast_log(LOG_DEBUG, "Invalid regex\n");
+ return 0;
+ }
+ --b;
+ } else if (*b == '\0') {
+ return -1;
+ }
+ } else if (*a == '\0') {
+ return 1;
+ }
+ ++a;
+ ++b;
+ }
+
+ return 0;
+}
+
+static struct ast_category *sort_by_name(struct ast_category *eroot)
+{
+ struct ast_category **linear;
+ struct ast_category *wp, *ret;
+ unsigned int i, max;
+
+ /* Count nodes */
+ for (max = 0, wp = eroot; wp != NULL; wp = wp->next)
+ ++max;
+
+ /* Decompose linked list into flat array */
+ linear = malloc(sizeof(struct ast_category *) * max);
+ if (linear == NULL) {
+ /* oder wie man am schönsten asterisk not-beendet */
+ abort();
+ }
+
+ for (i = 0, wp = eroot; wp != NULL; wp = wp->next) {
+ if (wp == NULL)
+ fprintf(stderr, "Damnit, should never happen\n");
+ linear[i++] = wp;
+ }
+
+ fprintf(stderr, "Something i=%u max=%u\n", i, max);
+ qsort(linear, i, sizeof(struct ast_category *), ast_regex_compare);
+
+ /* Rebuild linked list from sorted array */
+ for (wp = linear[0], i = 0; i < max - 1; ++i) {
+ wp->next = linear[i+1];
+ wp = wp->next;
+ }
+
+ wp->next = NULL;
+ ret = linear[0];
+ free(linear);
+ return ret;
+}
+
+void ast_config_sort_by_name(struct ast_config *cfg)
+{
+ if (cfg == NULL || cfg->root == NULL || cfg->root->name == NULL ||
+ cfg->root->next == NULL)
+ return;
+ cfg->root = sort_by_name(cfg->root);
+ return;
+}
+
struct ast_variable *ast_variable_new(const char *name, const char *value)
{
struct ast_variable *variable;
diff -dpru asterisk-1.2.19~/include/asterisk/config.h asterisk-1.2.19/include/asterisk/config.h
--- asterisk-1.2.19~/include/asterisk/config.h 2006-11-15 18:56:42.000000000 +0100
+++ asterisk-1.2.19/include/asterisk/config.h 2007-07-03 20:19:32.137821000 +0200
@@ -59,6 +59,8 @@ struct ast_config_engine {
struct ast_config_engine *next;
};
+void ast_config_sort_by_name(struct ast_config *);
+
/*! \brief Load a config file
* \param filename path of file to open. If no preceding '/' character, path is considered relative to AST_CONFIG_DIR
* Create a config structure from a given configuration file.
diff -dpru asterisk-1.2.19~/pbx/pbx_realtime.c asterisk-1.2.19/pbx/pbx_realtime.c
--- asterisk-1.2.19~/pbx/pbx_realtime.c 2005-11-29 19:24:39.000000000 +0100
+++ asterisk-1.2.19/pbx/pbx_realtime.c 2007-07-03 20:20:20.977821000 +0200
@@ -133,6 +133,8 @@ static struct ast_variable *realtime_swi
if (!var) {
cfg = ast_load_realtime_multientry(table, "exten LIKE", "\\_%", "context", context, "priority", pri, NULL);
if (cfg) {
+ ast_config_sort_by_name(cfg);
+
char *cat = ast_category_browse(cfg, NULL);
while(cat) {
More information about the asterisk-dev
mailing list