[Asterisk-cvs] asterisk config.c,1.52,1.53

markster at lists.digium.com markster at lists.digium.com
Sun Jan 30 00:24:44 CST 2005


Update of /usr/cvsroot/asterisk
In directory mongoose.digium.com:/tmp/cvs-serv28701

Modified Files:
	config.c 
Log Message:
Add category inheritance (bug #3099)


Index: config.c
===================================================================
RCS file: /usr/cvsroot/asterisk/config.c,v
retrieving revision 1.52
retrieving revision 1.53
diff -u -d -r1.52 -r1.53
--- config.c	28 Jan 2005 00:31:50 -0000	1.52
+++ config.c	30 Jan 2005 06:26:19 -0000	1.53
@@ -62,6 +62,7 @@
 
 struct ast_category {
 	char name[80];
+	int ignored;			/* do not let user of the config see this category */
 	struct ast_variable *root;
 	struct ast_variable *last;
 	struct ast_category *next;
@@ -123,13 +124,59 @@
 	return variable;
 }
 
+static struct ast_variable *variable_get(const struct ast_category *category, const char *name)
+{
+	struct ast_variable *variable;
+
+	for (variable = category->root; variable; variable = variable->next)
+		if (!strcasecmp(variable->name, name))
+			return variable;
+
+	return NULL;
+}
+
+static void variable_remove(struct ast_category *category, const struct ast_variable *variable)
+{
+	struct ast_variable *prev = category->root;
+
+	if (!prev)
+		return;
+
+	if (prev == variable) {
+		category->root = prev->next;
+		if (category->last == variable)
+			category->last = NULL;
+	} else {
+		while (prev->next && (prev->next != variable)) prev = prev->next;
+		if (prev->next) {
+			prev->next = variable->next;
+			if (category->last == variable)
+				category->last = prev;
+		}
+	}
+}
+
 void ast_variable_append(struct ast_category *category, struct ast_variable *variable)
 {
-	if (category->last)
-		category->last->next = variable;
-	else
-		category->root = variable;
-	category->last = variable;
+	/* Note: this function also implements "variable replacement"... if the
+	   new variable's value is empty, then existing variables of the same
+	   name in the category are removed (and the new variable is destroyed)
+	*/
+	if (variable->value && !ast_strlen_zero(variable->value)) {
+		if (category->last)
+			category->last->next = variable;
+		else
+			category->root = variable;
+		category->last = variable;
+	} else {
+		struct ast_variable *v;
+
+		while ((v = variable_get(category, variable->name))) {
+			variable_remove(category, v);
+			ast_variables_destroy(v);
+		}
+		ast_variables_destroy(variable);
+	}
 }
 
 void ast_variables_destroy(struct ast_variable *v)
@@ -181,6 +228,34 @@
 	return NULL;
 }
 
+static struct ast_variable *variable_clone(const struct ast_variable *old)
+{
+	struct ast_variable *new = ast_variable_new(old->name, old->value);
+
+	if (new) {
+		new->lineno = old->lineno;
+		new->object = old->object;
+		new->blanklines = old->blanklines;
+		/* TODO: clone comments? */
+	}
+
+	return new;
+}
+ 
+static void move_variables(struct ast_category *old, struct ast_category *new)
+{
+	struct ast_variable *var;
+	struct ast_variable *next;
+
+	next = old->root;
+	old->root = NULL;
+	for (var = next; var; var = next) {
+		next = var->next;
+		var->next = NULL;
+		ast_variable_append(new, var);
+	}
+}
+
 struct ast_category *ast_category_new(const char *name) 
 {
 	struct ast_category *category;
@@ -194,23 +269,28 @@
 	return category;
 }
 
-struct ast_category *ast_category_get(const struct ast_config *config, const char *category_name)
+static struct ast_category *category_get(const struct ast_config *config, const char *category_name, int ignored)
 {
 	struct ast_category *cat;
 
 	for (cat = config->root; cat; cat = cat->next) {
-		if (cat->name == category_name)
+		if (cat->name == category_name && (ignored || !cat->ignored))
 			return cat;
 	}
 
 	for (cat = config->root; cat; cat = cat->next) {
-		if (!strcasecmp(cat->name, category_name))
+		if (!strcasecmp(cat->name, category_name) && (ignored || !cat->ignored))
 			return cat;
 	}
 
 	return NULL;
 }
 
+struct ast_category *ast_category_get(const struct ast_config *config, const char *category_name)
+{
+	return category_get(config, category_name, 0);
+}
+
 int ast_category_exist(const struct ast_config *config, const char *category_name)
 {
 	return !!ast_category_get(config, category_name);
@@ -232,6 +312,13 @@
 	free(cat);
 }
 
+static struct ast_category *next_available_category(struct ast_category *cat)
+{
+	for (; cat && cat->ignored; cat = cat->next);
+
+	return cat;
+}
+
 char *ast_category_browse(struct ast_config *config, const char *prev)
 {	
 	struct ast_category *cat = NULL;
@@ -256,6 +343,9 @@
 			}
 		}
 	}
+	
+	if (cat)
+		cat = next_available_category(cat);
 
 	config->last_browse = cat;
 	if (cat)
@@ -279,6 +369,19 @@
 	strncpy(cat->name, name, sizeof(cat->name) - 1);
 }
 
+static void inherit_category(struct ast_category *new, const struct ast_category *base)
+{
+	struct ast_variable *var;
+
+	for (var = base->root; var; var = var->next) {
+		struct ast_variable *v;
+		
+		v = variable_clone(var);
+		if (v)
+			ast_variable_append(new, v);
+	}
+}
+
 struct ast_config *ast_config_new(void) 
 {
 	struct ast_config *config;
@@ -323,30 +426,69 @@
 static int process_text_line(struct ast_config *cfg, struct ast_category **cat, char *buf, int lineno, const char *configfile)
 {
 	char *c;
-	char *cur;
+	char *cur = buf;
 	struct ast_variable *v;
 	int object;
 
-	cur = ast_strip(buf);
-	if (ast_strlen_zero(cur))
-		return 0;
-
 	/* Actually parse the entry */
 	if (cur[0] == '[') {
+		struct ast_category *newcat = NULL;
+		char *catname;
+
 		/* A category header */
 		c = strchr(cur, ']');
 		if (!c) {
 			ast_log(LOG_WARNING, "parse error: no closing ']', line %d of %s\n", lineno, configfile);
 			return -1;
 		}
-		*c = '\0';
+		*c++ = '\0';
 		cur++;
-		*cat = ast_category_new(cur);
-		if (!*cat) {
+ 		if (*c++ != '(')
+ 			c = NULL;
+		catname = cur;
+		*cat = newcat = ast_category_new(catname);
+		if (!newcat) {
 			ast_log(LOG_WARNING, "Out of memory, line %d of %s\n", lineno, configfile);
 			return -1;
 		}
-		ast_category_append(cfg, *cat);
+ 		/* If there are options or categories to inherit from, process them now */
+ 		if (c) {
+ 			if (!(cur = strchr(c, ')'))) {
+ 				ast_log(LOG_WARNING, "parse error: no closing ')', line %d of %s\n", lineno, configfile);
+ 				return -1;
+ 			}
+ 			*cur = '\0';
+ 			while ((cur = strsep(&c, ","))) {
+				if (!strcasecmp(cur, "!")) {
+					(*cat)->ignored = 1;
+				} else if (!strcasecmp(cur, "+")) {
+					*cat = category_get(cfg, catname, 1);
+					if (!*cat) {
+						ast_destroy(cfg);
+						if (newcat)
+							ast_category_destroy(newcat);
+						ast_log(LOG_WARNING, "Category addition requested, but category '%s' does not exist, line %d of %s\n", catname, lineno, configfile);
+						return -1;
+					}
+					if (newcat) {
+						move_variables(newcat, *cat);
+						ast_category_destroy(newcat);
+						newcat = NULL;
+					}
+				} else {
+					struct ast_category *base;
+ 				
+					base = category_get(cfg, cur, 1);
+					if (!base) {
+						ast_log(LOG_WARNING, "Inheritance requested, but category '%s' does not exist, line %d of %s\n", cur, lineno, configfile);
+						return -1;
+					}
+					inherit_category(*cat, base);
+				}
+ 			}
+ 		}
+		if (newcat)
+			ast_category_append(cfg, *cat);
 	} else if (cur[0] == '#') {
 		/* A directive */
 		cur++;
@@ -518,9 +660,13 @@
 							new_buf = comment_p + 1;
 					}
 				}
-				if (process_buf && process_text_line(cfg, &cat, process_buf, lineno, filename)) {
-					cfg = NULL;
-					break;
+				if (process_buf) {
+					char *buf = ast_strip(process_buf);
+					if (!ast_strlen_zero(buf))
+						if (process_text_line(cfg, &cat, buf, lineno, filename)) {
+							cfg = NULL;
+							break;
+						}
 				}
 			}
 		}




More information about the svn-commits mailing list