[asterisk-commits] murf: trunk r82288 - /trunk/main/config.c

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Wed Sep 12 15:50:41 CDT 2007


Author: murf
Date: Wed Sep 12 15:50:40 2007
New Revision: 82288

URL: http://svn.digium.com/view/asterisk?view=rev&rev=82288
Log:
This fix closes issue #10642 -- it's not perfect, but should retain most blank lines in config files, via read/write cycles.

Modified:
    trunk/main/config.c

Modified: trunk/main/config.c
URL: http://svn.digium.com/view/asterisk/trunk/main/config.c?view=diff&rev=82288&r1=82287&r2=82288
==============================================================================
--- trunk/main/config.c (original)
+++ trunk/main/config.c Wed Sep 12 15:50:40 2007
@@ -54,6 +54,7 @@
 #include "asterisk/utils.h"
 #include "asterisk/channel.h"
 #include "asterisk/app.h"
+#include "asterisk/astobj2.h"
 
 #define MAX_NESTED_COMMENTS 128
 #define COMMENT_START ";--"
@@ -162,6 +163,40 @@
 	return x;
 }
 
+/* I need to keep track of each config file, and all its inclusions,
+   so that we can track blank lines in each */
+
+struct inclfile
+{
+	char *fname;
+	int lineno;
+};
+
+static int hash_string(const void *obj, const int flags)
+{
+	char *str = ((struct inclfile*)obj)->fname;
+	int total;
+
+	for (total=0; *str; str++)
+	{
+		unsigned int tmp = total;
+		total <<= 1; /* multiply by 2 */
+		total += tmp; /* multiply by 3 */
+		total <<= 2; /* multiply by 12 */
+		total += tmp; /* multiply by 13 */
+        
+		total += ((unsigned int)(*str));
+	}
+	if (total < 0)
+		total = -total;
+	return total;
+}
+
+static int hashtab_compare_strings(void *a, void *b, int flags)
+{
+	const struct inclfile *ae = a, *be = b;
+	return !strcmp(ae->fname, be->fname) ? CMP_MATCH : 0;
+}
 
 static struct ast_config_map {
 	struct ast_config_map *next;
@@ -1320,8 +1355,18 @@
 	fprintf(f1, ";!\n");
 }
 
-static void set_fn(char *fn, int fn_size, const char *file, const char *configfile)
-{
+static void   inclfile_destroy(void *obj)
+{
+	const struct inclfile *o = obj;
+	if (o->fname)
+		free(o->fname);
+}
+
+
+static void set_fn(char *fn, int fn_size, const char *file, const char *configfile, struct ao2_container *fileset, struct inclfile **fi)
+{
+	struct inclfile lookup;
+	
 	if (!file || file[0] == 0) {
 		if (configfile[0] == '/')
 			ast_copy_string(fn, configfile, fn_size);
@@ -1331,6 +1376,54 @@
 		ast_copy_string(fn, file, fn_size);
 	else
 		snprintf(fn, fn_size, "%s/%s", ast_config_AST_CONFIG_DIR, file);
+	lookup.fname = fn;
+	*fi = ao2_find(fileset, &lookup, OBJ_POINTER);
+	if (!(*fi)) {
+		/* set up a file scratch pad */
+		struct inclfile *fx = ao2_alloc(sizeof(struct inclfile), inclfile_destroy);
+		fx->fname = ast_strdup(fn);
+		fx->lineno = 1;
+		*fi = fx;
+		ao2_link(fileset, fx);
+		ao2_ref(fx,1); /* bump the ref count, so it looks like we just got the ref from find */
+	}
+}
+
+static int count_linefeeds(char *str)
+{
+	int count = 0;
+	while (*str) {
+		if (*str =='\n')
+			count++;
+		str++;
+	}
+	return count;
+}
+
+static int count_linefeeds_in_comments(struct ast_comment *x)
+{
+	int count = 0;
+	while (x)
+	{
+		count += count_linefeeds(x->cmt);
+		x = x->next;
+	}
+	return count;
+}
+
+static void insert_leading_blank_lines(FILE *fp, struct inclfile *fi, struct ast_comment *precomments, int lineno)
+{
+	int precomment_lines = count_linefeeds_in_comments(precomments);
+	int i;
+
+	/* I don't have to worry about those ;! comments, they are
+	   stored in the precomments, but not printed back out.
+	   I did have to make sure that comments following
+	   the ;! header comments were not also deleted in the process */
+	for (i=fi->lineno;i<lineno - precomment_lines; i++) {
+		fprintf(fp,"\n");
+	}
+	fi->lineno = lineno+1; /* Advance the file lineno */
 }
 
 int config_text_file_save(const char *configfile, const struct ast_config *cfg, const char *generator)
@@ -1342,6 +1435,8 @@
 	struct ast_comment *cmt;
 	struct ast_config_include *incl;
 	int blanklines = 0;
+	struct ao2_container *fileset = ao2_container_alloc(180000, hash_string, hashtab_compare_strings);
+	struct inclfile *fi = 0;
 
 	/* reset all the output flags, in case this isn't our first time saving this data */
 
@@ -1356,7 +1451,7 @@
 		if (!incl->exec) { /* leave the execs alone -- we'll write out the #exec directives, but won't zero out the include files or exec files*/
 			FILE *f1;
 
-			set_fn(fn, sizeof(fn), incl->included_file, configfile); /* normally, fn is just set to incl->included_file, prepended with config dir if relative */
+			set_fn(fn, sizeof(fn), incl->included_file, configfile, fileset, &fi); /* normally, fn is just set to incl->included_file, prepended with config dir if relative */
 			f1 = fopen(fn,"w");
 			if (f1) {
 				gen_header(f1, configfile, fn, generator);
@@ -1365,10 +1460,12 @@
 				ast_debug(1, "Unable to open for writing: %s\n", fn);
 				ast_verb(2, "Unable to write %s (%s)", fn, strerror(errno));
 			}
-		}
-	}
-
-	set_fn(fn, sizeof(fn), 0, configfile); /* just set fn to absolute ver of configfile */
+			ao2_ref(fi,-1); /* we are giving up this reference to the object ptd to by fi */
+			fi = 0;
+		}
+	}
+
+	set_fn(fn, sizeof(fn), 0, configfile, fileset, &fi); /* just set fn to absolute ver of configfile */
 #ifdef __CYGWIN__	
 	if ((f = fopen(fn, "w+"))) {
 #else
@@ -1378,18 +1475,20 @@
 		gen_header(f, configfile, fn, generator);
 		cat = cfg->root;
 		fclose(f);
+		ao2_ref(fi,-1); /* we are giving up this reference to the object ptd to by fi */
 		
 		/* from here out, we open each involved file and concat the stuff we need to add to the end and immediately close... */
 		/* since each var, cat, and associated comments can come from any file, we have to be 
 		   mobile, and open each file, print, and close it on an entry-by-entry basis */
 
 		while (cat) {
-			set_fn(fn, sizeof(fn), cat->file, configfile);
+			set_fn(fn, sizeof(fn), cat->file, configfile, fileset, &fi);
 			f = fopen(fn, "a");
 			if (!f)
 			{
 				ast_debug(1, "Unable to open for writing: %s\n", fn);
 				ast_verb(2, "Unable to write %s (%s)", fn, strerror(errno));
+				ao2_ref(fileset, -1);
 				return -1;
 			}
 
@@ -1406,10 +1505,18 @@
 				}
 			}
 			
+			insert_leading_blank_lines(f, fi, cat->precomments, cat->lineno);
 			/* Dump section with any appropriate comment */
 			for (cmt = cat->precomments; cmt; cmt=cmt->next) {
-				if (cmt->cmt[0] != ';' || cmt->cmt[1] != '!')
-					fprintf(f,"%s", cmt->cmt);
+				char *cmtp = cmt->cmt;
+				while (*cmtp == ';' && *(cmtp+1) == '!') {
+					char *cmtp2 = strchr(cmtp+1, '\n');
+					if (cmtp2)
+						cmtp = cmtp2+1;
+					else cmtp = 0;
+				}
+				if (cmtp)
+					fprintf(f,"%s", cmtp);
 			}
 			if (!cat->precomments)
 				fprintf(f,"\n");
@@ -1424,15 +1531,20 @@
 					fprintf(f,"%s", cmt->cmt);
 			}
 			fclose(f);
+			ao2_ref(fi,-1); /* we are giving up this reference to the object ptd to by fi */
+			fi = 0;
 			
 			var = cat->root;
 			while (var) {
-				set_fn(fn, sizeof(fn), var->file, configfile);
+				set_fn(fn, sizeof(fn), var->file, configfile, fileset, &fi);
 				f = fopen(fn, "a");
 				if (!f)
 				{
 					ast_debug(1, "Unable to open for writing: %s\n", fn);
 					ast_verb(2, "Unable to write %s (%s)", fn, strerror(errno));
+					ao2_ref(fi,-1); /* we are giving up this reference to the object ptd to by fi */
+					fi = 0;
+					ao2_ref(fileset, -1);
 					return -1;
 				}
 				
@@ -1449,6 +1561,7 @@
 					}
 				}
 				
+				insert_leading_blank_lines(f, fi, var->precomments, var->lineno);
 				for (cmt = var->precomments; cmt; cmt=cmt->next) {
 					if (cmt->cmt[0] != ';' || cmt->cmt[1] != '!')
 						fprintf(f,"%s", cmt->cmt);
@@ -1468,6 +1581,8 @@
 				}
 				
 				fclose(f);
+				ao2_ref(fi,-1); /* we are giving up this reference to the object ptd to by fi */
+				fi = 0;
 				
 				var = var->next;
 			}
@@ -1478,6 +1593,8 @@
 	} else {
 		ast_debug(1, "Unable to open for writing: %s\n", fn);
 		ast_verb(2, "Unable to write (%s)", strerror(errno));
+		ao2_ref(fi,-1); /* we are giving up this reference to the object ptd to by fi */
+		ao2_ref(fileset, -1);
 		return -1;
 	}
 
@@ -1487,12 +1604,15 @@
 	for (incl=cfg->includes; incl; incl = incl->next) {
 		if (!incl->output) {
 			/* open the respective file */
-			set_fn(fn, sizeof(fn), incl->include_location_file, configfile);
+			set_fn(fn, sizeof(fn), incl->include_location_file, configfile, fileset, &fi);
 			f = fopen(fn, "a");
 			if (!f)
 			{
 				ast_debug(1, "Unable to open for writing: %s\n", fn);
 				ast_verb(2, "Unable to write %s (%s)", fn, strerror(errno));
+				ao2_ref(fi,-1); /* we are giving up this reference to the object ptd to by fi */
+				fi = 0;
+				ao2_ref(fileset, -1);
 				return -1;
 			}
 			
@@ -1503,8 +1623,11 @@
 				fprintf(f,"#include \"%s\"\n", incl->included_file);
 			fclose(f);
 			incl->output = 1;
-		}
-	}
+			ao2_ref(fi,-1); /* we are giving up this reference to the object ptd to by fi */
+			fi = 0;
+		}
+	}
+	ao2_ref(fileset, -1); /* this should destroy the hash container */
 				
 	return 0;
 }




More information about the asterisk-commits mailing list