[asterisk-commits] murf: branch murf/bug8684-trunk r81357 - /team/murf/bug8684-trunk/utils/

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Wed Aug 29 15:07:13 CDT 2007


Author: murf
Date: Wed Aug 29 15:07:13 2007
New Revision: 81357

URL: http://svn.digium.com/view/asterisk?view=rev&rev=81357
Log:
Try and reflect all the applicable changes to extconf.c

Modified:
    team/murf/bug8684-trunk/utils/extconf.c

Modified: team/murf/bug8684-trunk/utils/extconf.c
URL: http://svn.digium.com/view/asterisk/team/murf/bug8684-trunk/utils/extconf.c?view=diff&rev=81357&r1=81356&r2=81357
==============================================================================
--- team/murf/bug8684-trunk/utils/extconf.c (original)
+++ team/murf/bug8684-trunk/utils/extconf.c Wed Aug 29 15:07:13 2007
@@ -620,6 +620,8 @@
 	char name[80];
 	int ignored;			/*!< do not let user of the config see this category */
 	int include_level;	
+    char *file;                /*!< the file name from whence this declaration was read */
+    int lineno;
 	struct ast_comment *precomments;
 	struct ast_comment *sameline;
 	struct ast_variable *root;
@@ -634,9 +636,22 @@
 	struct ast_category *last_browse;		/*!< used to cache the last category supplied via category_browse */
 	int include_level;
 	int max_include_level;
+    struct ast_config_include *includes;  /*!< a list of inclusions, which should describe the entire tree */
 };
 
-typedef struct ast_config *config_load_func(const char *database, const char *table, const char *configfile, struct ast_config *config, int withcomments);
+struct ast_config_include {
+	char *include_location_file;     /*!< file name in which the include occurs */
+	int  include_location_lineno;    /*!< lineno where include occurred */
+	int  exec;                       /*!< set to non-zero if itsa #exec statement */
+	char *exec_file;                 /*!< if it's an exec, you'll have both the /var/tmp to read, and the original script */
+	char *included_file;             /*!< file name included */
+	int inclusion_count;             /*!< if the file is included more than once, a running count thereof -- but, worry not,
+									   we explode the instances and will include those-- so all entries will be unique */
+	int output;                      /*!< a flag to indicate if the inclusion has been output */
+	struct ast_config_include *next; /*!< ptr to next inclusion in the list */
+};
+
+typedef struct ast_config *config_load_func(const char *database, const char *table, const char *configfile, struct ast_config *config, int withcomments, const char *suggested_include_file);
 typedef struct ast_variable *realtime_var_get(const char *database, const char *table, va_list ap);
 typedef struct ast_config *realtime_multi_get(const char *database, const char *table, va_list ap);
 typedef int realtime_update(const char *database, const char *table, const char *keyfield, const char *entity, va_list ap);
@@ -652,6 +667,83 @@
 };
 
 static struct ast_config_engine *config_engine_list;
+
+/* taken from strings.h */
+
+static force_inline int ast_strlen_zero(const char *s)
+{
+	return (!s || (*s == '\0'));
+}
+
+#define S_OR(a, b)	(!ast_strlen_zero(a) ? (a) : (b))
+
+AST_INLINE_API(
+void ast_copy_string(char *dst, const char *src, size_t size),
+{
+	while (*src && size) {
+		*dst++ = *src++;
+		size--;
+	}
+	if (__builtin_expect(!size, 0))
+		dst--;
+	*dst = '\0';
+}
+)
+
+AST_INLINE_API(
+char *ast_skip_blanks(const char *str),
+{
+	while (*str && *str < 33)
+		str++;
+	return (char *)str;
+}
+)
+
+/*!
+  \brief Trims trailing whitespace characters from a string.
+  \param ast_trim_blanks function being used
+  \param str the input string
+  \return a pointer to the modified string
+ */
+AST_INLINE_API(
+char *ast_trim_blanks(char *str),
+{
+	char *work = str;
+
+	if (work) {
+		work += strlen(work) - 1;
+		/* It's tempting to only want to erase after we exit this loop, 
+		   but since ast_trim_blanks *could* receive a constant string
+		   (which we presumably wouldn't have to touch), we shouldn't
+		   actually set anything unless we must, and it's easier just
+		   to set each position to \0 than to keep track of a variable
+		   for it */
+		while ((work >= str) && *work < 33)
+			*(work--) = '\0';
+	}
+	return str;
+}
+)
+
+/*!
+  \brief Strip leading/trailing whitespace from a string.
+  \param s The string to be stripped (will be modified).
+  \return The stripped string.
+
+  This functions strips all leading and trailing whitespace
+  characters from the input string, and returns a pointer to
+  the resulting string. The string is modified in place.
+*/
+AST_INLINE_API(
+char *ast_strip(char *s),
+{
+	s = ast_skip_blanks(s);
+	if (s)
+		ast_trim_blanks(s);
+	return s;
+} 
+)
+
 
 /* from config.h */
 
@@ -669,13 +761,16 @@
 };
 
 static const char *ast_variable_retrieve(const struct ast_config *config, const char *category, const char *variable);
-static struct ast_config *config_text_file_load(const char *database, const char *table, const char *filename, struct ast_config *cfg, int withcomments);
+static struct ast_config *config_text_file_load(const char *database, const char *table, const char *filename, struct ast_config *cfg, int withcomments, const char *suggested_include_file);
 
 struct ast_config *localized_config_load_with_comments(const char *filename);
 static char *ast_category_browse(struct ast_config *config, const char *prev);
 static struct ast_variable *ast_variable_browse(const struct ast_config *config, const char *category);
 static void ast_variables_destroy(struct ast_variable *v);
 static void ast_config_destroy(struct ast_config *cfg);
+static struct ast_config_include *ast_include_new(struct ast_config *conf, const char *from_file, const char *included_file, int is_exec, const char *exec_file, int from_lineno, char *real_included_file_name, int real_included_file_name_size);
+static struct ast_config_include *ast_include_find(struct ast_config *conf, const char *included_file);
+void localized_ast_include_rename(struct ast_config *conf, const char *from_file, const char *to_file);
 
 static struct ast_variable *ast_variable_new(const char *name, const char *value, const char *filename);
 
@@ -695,6 +790,107 @@
 
 	return variable;
 }
+
+static struct ast_config_include *ast_include_new(struct ast_config *conf, const char *from_file, const char *included_file, int is_exec, const char *exec_file, int from_lineno, char *real_included_file_name, int real_included_file_name_size)
+{
+	/* a file should be included ONCE. Otherwise, if one of the instances is changed,
+       then all be changed. -- how do we know to include it? -- Handling modified 
+       instances is possible, I'd have
+       to create a new master for each instance. */
+	struct ast_config_include *inc;
+    
+	inc = ast_include_find(conf, included_file);
+	if (inc)
+	{
+		inc->inclusion_count++;
+		snprintf(real_included_file_name, real_included_file_name_size, "%s~~%d", included_file, inc->inclusion_count);
+		ast_log(LOG_WARNING,"'%s', line %d:  Same File included more than once! This data will be saved in %s if saved back to disk.\n", from_file, from_lineno, real_included_file_name);
+	} else
+		*real_included_file_name = 0;
+	
+	inc = ast_calloc(1,sizeof(struct ast_config_include));
+	inc->include_location_file = ast_strdup(from_file);
+	inc->include_location_lineno = from_lineno;
+	if (!ast_strlen_zero(real_included_file_name))
+		inc->included_file = ast_strdup(real_included_file_name);
+	else
+		inc->included_file = ast_strdup(included_file);
+	
+	inc->exec = is_exec;
+	if (is_exec)
+		inc->exec_file = ast_strdup(exec_file);
+	
+	/* attach this new struct to the conf struct */
+	inc->next = conf->includes;
+	conf->includes = inc;
+    
+	return inc;
+}
+
+void localized_ast_include_rename(struct ast_config *conf, const char *from_file, const char *to_file)
+{
+	struct ast_config_include *incl;
+	struct ast_category *cat;
+	struct ast_variable *v;
+    
+	int from_len = strlen(from_file);
+	int to_len = strlen(to_file);
+    
+	if (strcmp(from_file, to_file) == 0) /* no use wasting time if the name is the same */
+		return;
+	
+	/* the manager code allows you to read in one config file, then
+       write it back out under a different name. But, the new arrangement
+	   ties output lines to the file name. So, before you try to write
+       the config file to disk, better riffle thru the data and make sure
+       the file names are changed.
+	*/
+	/* file names are on categories, includes (of course), and on variables. So,
+	   traverse all this and swap names */
+	
+	for (incl = conf->includes; incl; incl=incl->next) {
+		if (strcmp(incl->include_location_file,from_file) == 0) {
+			if (from_len >= to_len)
+				strcpy(incl->include_location_file, to_file);
+			else {
+				free(incl->include_location_file);
+				incl->include_location_file = strdup(to_file);
+			}
+		}
+	}
+	for (cat = conf->root; cat; cat = cat->next) {
+		if (strcmp(cat->file,from_file) == 0) {
+			if (from_len >= to_len)
+				strcpy(cat->file, to_file);
+			else {
+				free(cat->file);
+				cat->file = strdup(to_file);
+			}
+		}
+		for (v = cat->root; v; v = v->next) {
+			if (strcmp(v->file,from_file) == 0) {
+				if (from_len >= to_len)
+					strcpy(v->file, to_file);
+				else {
+					free(v->file);
+					v->file = strdup(to_file);
+				}
+			}
+		}
+	}
+}
+
+static struct ast_config_include *ast_include_find(struct ast_config *conf, const char *included_file)
+{
+	struct ast_config_include *x;
+	for (x=conf->includes;x;x=x->next)
+	{
+		if (strcmp(x->included_file,included_file) == 0)
+			return x;
+	}
+	return 0;
+}
+
 
 static void ast_variable_append(struct ast_category *category, struct ast_variable *variable);
 
@@ -794,6 +990,22 @@
 	}
 }
 
+static void ast_includes_destroy(struct ast_config_include *incls)
+{
+	struct ast_config_include *incl,*inclnext;
+    
+	for (incl=incls; incl; incl = inclnext) {
+		inclnext = incl->next;
+		if (incl->include_location_file)
+			free(incl->include_location_file);
+		if (incl->exec_file)
+			free(incl->exec_file);
+		if (incl->included_file)
+			free(incl->included_file);
+		free(incl);
+	}
+}
+
 static void ast_config_destroy(struct ast_config *cfg)
 {
 	struct ast_category *cat, *catn;
@@ -801,6 +1013,8 @@
 	if (!cfg)
 		return;
 
+	ast_includes_destroy(cfg->includes);
+	
 	cat = cfg->root;
 	while (cat) {
 		ast_variables_destroy(cat->root);
@@ -2434,83 +2648,6 @@
 static void pbx_substitute_variables_helper(struct ast_channel *c,const char *cp1,char *cp2,int count);
 
 
-/* taken from strings.h */
-
-static force_inline int ast_strlen_zero(const char *s)
-{
-	return (!s || (*s == '\0'));
-}
-
-#define S_OR(a, b)	(!ast_strlen_zero(a) ? (a) : (b))
-
-AST_INLINE_API(
-void ast_copy_string(char *dst, const char *src, size_t size),
-{
-	while (*src && size) {
-		*dst++ = *src++;
-		size--;
-	}
-	if (__builtin_expect(!size, 0))
-		dst--;
-	*dst = '\0';
-}
-)
-
-AST_INLINE_API(
-char *ast_skip_blanks(const char *str),
-{
-	while (*str && *str < 33)
-		str++;
-	return (char *)str;
-}
-)
-
-/*!
-  \brief Trims trailing whitespace characters from a string.
-  \param ast_trim_blanks function being used
-  \param str the input string
-  \return a pointer to the modified string
- */
-AST_INLINE_API(
-char *ast_trim_blanks(char *str),
-{
-	char *work = str;
-
-	if (work) {
-		work += strlen(work) - 1;
-		/* It's tempting to only want to erase after we exit this loop, 
-		   but since ast_trim_blanks *could* receive a constant string
-		   (which we presumably wouldn't have to touch), we shouldn't
-		   actually set anything unless we must, and it's easier just
-		   to set each position to \0 than to keep track of a variable
-		   for it */
-		while ((work >= str) && *work < 33)
-			*(work--) = '\0';
-	}
-	return str;
-}
-)
-
-/*!
-  \brief Strip leading/trailing whitespace from a string.
-  \param s The string to be stripped (will be modified).
-  \return The stripped string.
-
-  This functions strips all leading and trailing whitespace
-  characters from the input string, and returns a pointer to
-  the resulting string. The string is modified in place.
-*/
-AST_INLINE_API(
-char *ast_strip(char *s),
-{
-	s = ast_skip_blanks(s);
-	if (s)
-		ast_trim_blanks(s);
-	return s;
-} 
-)
-
-
 /* stolen from callerid.c */
 
 /*! \brief Clean up phone string
@@ -3163,12 +3300,12 @@
 				ret = eng;
 		}
 	}
-
+	
 	
 	/* if we found a mapping, but the engine is not available, then issue a warning */
 	if (map && !ret)
 		ast_log(LOG_WARNING, "Realtime mapping for '%s' found to engine '%s', but the engine is not available\n", map->name, map->driver);
-
+	
 	return ret;
 }
 
@@ -3179,15 +3316,17 @@
 	return cfg->current;
 }
 
-static struct ast_category *ast_category_new(const char *name);
-
-static struct ast_category *ast_category_new(const char *name) 
+static struct ast_category *ast_category_new(const char *name, const char *in_file, int lineno);
+
+static struct ast_category *ast_category_new(const char *name, const char *in_file, int lineno)
 {
 	struct ast_category *category;
 
 	if ((category = ast_calloc(1, sizeof(*category))))
 		ast_copy_string(category->name, name, sizeof(category->name));
-	return category;
+	category->file = strdup(in_file);
+	category->lineno = lineno; /* if you don't know the lineno, set it to 999999 or something real big */
+ 	return category;
 }
 
 struct ast_category *localized_category_get(const struct ast_config *config, const char *category_name);
@@ -3239,6 +3378,9 @@
 static void ast_category_destroy(struct ast_category *cat)
 {
 	ast_variables_destroy(cat->root);
+	if (cat->file)
+		free(cat->file);
+	
 	free(cat);
 }
 
@@ -3248,9 +3390,9 @@
 };
 
 
-static struct ast_config *ast_config_internal_load(const char *filename, struct ast_config *cfg, int withcomments);
-
-static struct ast_config *ast_config_internal_load(const char *filename, struct ast_config *cfg, int withcomments)
+static struct ast_config *ast_config_internal_load(const char *filename, struct ast_config *cfg, int withcomments, const char *suggested_incl_file);
+
+static struct ast_config *ast_config_internal_load(const char *filename, struct ast_config *cfg, int withcomments, const char *suggested_incl_file)
 {
 	char db[256];
 	char table[256];
@@ -3282,7 +3424,7 @@
 		}
 	}
 
-	result = loader->load_func(db, table, filename, cfg, withcomments);
+	result = loader->load_func(db, table, filename, cfg, withcomments, suggested_incl_file);
 	/* silence is golden 
 	   ast_log(LOG_WARNING, "finished internal loading file %s level=%d\n", filename, cfg->include_level);
 	*/
@@ -3294,7 +3436,7 @@
 }
 
 
-static int process_text_line(struct ast_config *cfg, struct ast_category **cat, char *buf, int lineno, const char *configfile, int withcomments)
+static int process_text_line(struct ast_config *cfg, struct ast_category **cat, char *buf, int lineno, const char *configfile, int withcomments, const char *suggested_include_file)
 {
 	char *c;
 	char *cur = buf;
@@ -3318,9 +3460,11 @@
  		if (*c++ != '(')
  			c = NULL;
 		catname = cur;
-		if (!(*cat = newcat = ast_category_new(catname))) {
+		if (!(*cat = newcat = ast_category_new(catname, ast_strlen_zero(suggested_include_file)?configfile:suggested_include_file, lineno))) {
 			return -1;
 		}
+		(*cat)->lineno = lineno;
+        
 		/* add comments */
 		if (withcomments && comment_buffer && comment_buffer[0] ) {
 			newcat->precomments = ALLOC_COMMENT(comment_buffer);
@@ -3393,10 +3537,15 @@
 		}
 		if (do_include || do_exec) {
 			if (c) {
+				char *cur2;
+				char real_inclusion_name[256];
+				struct ast_config_include *inclu;
+                
 				/* Strip off leading and trailing "'s and <>'s */
 				while((*c == '<') || (*c == '>') || (*c == '\"')) c++;
 				/* Get rid of leading mess */
 				cur = c;
+				cur2 = cur;
 				while (!ast_strlen_zero(cur)) {
 					c = cur + strlen(cur) - 1;
 					if ((*c == '>') || (*c == '<') || (*c == '\"'))
@@ -3416,7 +3565,10 @@
 				/* A #include */
 				/* ast_log(LOG_WARNING, "Reading in included file %s withcomments=%d\n", cur, withcomments); */
 				
-				do_include = ast_config_internal_load(cur, cfg, withcomments) ? 1 : 0;
+				/* record this inclusion */
+				inclu = ast_include_new(cfg, configfile, cur, do_exec, cur2, lineno, real_inclusion_name, sizeof(real_inclusion_name));
+				
+				do_include = ast_config_internal_load(cur, cfg, withcomments, real_inclusion_name) ? 1 : 0;
 				if(!ast_strlen_zero(exec_file))
 					unlink(exec_file);
 				if(!do_include)
@@ -3492,7 +3644,7 @@
 }
 
 
-static struct ast_config *config_text_file_load(const char *database, const char *table, const char *filename, struct ast_config *cfg, int withcomments)
+static struct ast_config *config_text_file_load(const char *database, const char *table, const char *filename, struct ast_config *cfg, int withcomments, const char *suggested_include_file)
 {
 	char fn[256];
 	char buf[8192];
@@ -3638,7 +3790,7 @@
 				if (process_buf) {
 					char *buf = ast_strip(process_buf);
 					if (!ast_strlen_zero(buf)) {
-						if (process_text_line(cfg, &cat, buf, lineno, filename, withcomments)) {
+						if (process_text_line(cfg, &cat, buf, lineno, filename, withcomments, suggested_include_file)) {
 							cfg = NULL;
 							break;
 						}
@@ -3698,7 +3850,7 @@
 	if (!cfg)
 		return NULL;
 
-	result = ast_config_internal_load(filename, cfg, 0);
+	result = ast_config_internal_load(filename, cfg, 0, "");
 	if (!result)
 		ast_config_destroy(cfg);
 
@@ -3716,7 +3868,7 @@
 	if (!cfg)
 		return NULL;
 
-	result = ast_config_internal_load(filename, cfg, 1);
+	result = ast_config_internal_load(filename, cfg, 1, "");
 	if (!result)
 		ast_config_destroy(cfg);
 
@@ -3772,26 +3924,94 @@
 	cfg->current = (struct ast_category *) cat;
 }
 
+/* NOTE: categories and variables each have a file and lineno attribute. On a save operation, these are used to determine
+   which file and line number to write out to. Thus, an entire hierarchy of config files (via #include statements) can be
+   recreated. BUT, care must be taken to make sure that every cat and var has the proper file name stored, or you may
+   be shocked and mystified as to why things are not showing up in the files! 
+   
+   Also, All #include/#exec statements are recorded in the "includes" LL in the ast_config structure. The file name
+   and line number are stored for each include, plus the name of the file included, so that these statements may be
+   included in the output files on a file_save operation. 
+   
+   The lineno's are really just for relative placement in the file. There is no attempt to make sure that blank lines
+   are included to keep the lineno's the same between input and output. The lineno fields are used mainly to determine
+   the position of the #include and #exec directives. So, blank lines tend to disappear from a read/rewrite operation,
+   and a header gets added.
+   
+   vars and category heads are output in the order they are stored in the config file. So, if the software
+   shuffles these at all, then the placement of #include directives might get a little mixed up, because the
+   file/lineno data probably won't get changed.
+   
+*/
+
+static void gen_header(FILE *f1, const char *configfile, const char *fn, const char *generator)
+{
+	char date[256]="";
+	time_t t;
+	time(&t);
+	ast_copy_string(date, ctime(&t), sizeof(date));
+	
+	fprintf(f1, ";!\n");
+	fprintf(f1, ";! Automatically generated configuration file\n");
+	if (strcmp(configfile, fn))
+		fprintf(f1, ";! Filename: %s (%s)\n", configfile, fn);
+	else
+		fprintf(f1, ";! Filename: %s\n", configfile);
+	fprintf(f1, ";! Generator: %s\n", generator);
+	fprintf(f1, ";! Creation Date: %s", date);
+	fprintf(f1, ";!\n");
+}
+
+static void set_fn(char *fn, int fn_size, const char *file, const char *configfile)
+{
+	if (!file || file[0] == 0) {
+		if (configfile[0] == '/')
+			ast_copy_string(fn, configfile, fn_size);
+		else
+			snprintf(fn, fn_size, "%s/%s", ast_config_AST_CONFIG_DIR, configfile);
+	} else if (file[0] == '/') 
+		ast_copy_string(fn, file, fn_size);
+	else
+		snprintf(fn, fn_size, "%s/%s", ast_config_AST_CONFIG_DIR, file);
+}
+
 int localized_config_text_file_save(const char *configfile, const struct ast_config *cfg, const char *generator);
 
 int localized_config_text_file_save(const char *configfile, const struct ast_config *cfg, const char *generator)
 {
 	FILE *f;
 	char fn[256];
-	char date[256]="";
-	time_t t;
 	struct ast_variable *var;
 	struct ast_category *cat;
 	struct ast_comment *cmt;
+	struct ast_config_include *incl;
 	int blanklines = 0;
-
-	if (configfile[0] == '/') {
-		ast_copy_string(fn, configfile, sizeof(fn));
-	} else {
-		snprintf(fn, sizeof(fn), "%s/%s", ast_config_AST_CONFIG_DIR, configfile);
-	}
-	time(&t);
-	ast_copy_string(date, ctime(&t), sizeof(date));
+	
+	/* reset all the output flags, in case this isn't our first time saving this data */
+	
+	for (incl=cfg->includes; incl; incl = incl->next)
+		incl->output = 0;
+	
+	/* go thru all the inclusions and make sure all the files involved (configfile plus all its inclusions)
+	   are all truncated to zero bytes and have that nice header*/
+	
+	for (incl=cfg->includes; incl; incl = incl->next)
+	{
+		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 */
+			f1 = fopen(fn,"w");
+			if (f1) {
+				gen_header(f1, configfile, fn, generator);
+				fclose(f1); /* this should zero out the file */
+			} else {
+				ast_verbose(VERBOSE_PREFIX_2 "Unable to write %s (%s)", fn, strerror(errno));
+			}
+		}
+	}
+	
+	set_fn(fn, sizeof(fn), 0, configfile); /* just set fn to absolute ver of configfile */
 #ifdef __CYGWIN__	
 	if ((f = fopen(fn, "w+"))) {
 #else
@@ -3799,36 +4019,76 @@
 #endif	    
 		if (option_verbose > 1)
 			ast_verbose(VERBOSE_PREFIX_2 "Saving '%s': ", fn);
-		fprintf(f, ";!\n");
-		fprintf(f, ";! Automatically generated configuration file\n");
-		if (strcmp(configfile, fn))
-			fprintf(f, ";! Filename: %s (%s)\n", configfile, fn);
-		else
-			fprintf(f, ";! Filename: %s\n", configfile);
-		fprintf(f, ";! Generator: %s\n", generator);
-		fprintf(f, ";! Creation Date: %s", date);
-		fprintf(f, ";!\n");
+
+		gen_header(f, configfile, fn, generator);
 		cat = cfg->root;
+		fclose(f);
+        
+		/* 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);
+			f = fopen(fn, "a");
+			if (!f)
+			{
+				ast_verbose(VERBOSE_PREFIX_2 "Unable to write %s (%s)", fn, strerror(errno));
+				return -1;
+			}
+			
+			/* dump any includes that happen before this category header */
+			for (incl=cfg->includes; incl; incl = incl->next) {
+				if (strcmp(incl->include_location_file, cat->file) == 0){
+					if (cat->lineno > incl->include_location_lineno && !incl->output) {
+						if (incl->exec)
+							fprintf(f,"#exec \"%s\"\n", incl->exec_file);
+						else
+							fprintf(f,"#include \"%s\"\n", incl->included_file);
+						incl->output = 1;
+					}
+				}
+			}
+            
 			/* Dump section with any appropriate comment */
-			for (cmt = cat->precomments; cmt; cmt=cmt->next)
-			{
+			for (cmt = cat->precomments; cmt; cmt=cmt->next) {
 				if (cmt->cmt[0] != ';' || cmt->cmt[1] != '!')
 					fprintf(f,"%s", cmt->cmt);
 			}
 			if (!cat->precomments)
 				fprintf(f,"\n");
 			fprintf(f, "[%s]", cat->name);
-			for(cmt = cat->sameline; cmt; cmt=cmt->next)
-			{
+			for(cmt = cat->sameline; cmt; cmt=cmt->next) {
 				fprintf(f,"%s", cmt->cmt);
 			}
 			if (!cat->sameline)
 				fprintf(f,"\n");
+			fclose(f);
+            
 			var = cat->root;
 			while(var) {
-				for (cmt = var->precomments; cmt; cmt=cmt->next)
+				set_fn(fn, sizeof(fn), var->file, configfile);
+				f = fopen(fn, "a");
+				if (!f)
 				{
+					ast_verbose(VERBOSE_PREFIX_2 "Unable to write %s (%s)", fn, strerror(errno));
+					return -1;
+				}
+                
+				/* dump any includes that happen before this category header */
+				for (incl=cfg->includes; incl; incl = incl->next) {
+					if (strcmp(incl->include_location_file, var->file) == 0){
+						if (var->lineno > incl->include_location_lineno && !incl->output) {
+							if (incl->exec)
+								fprintf(f,"#exec \"%s\"\n", incl->exec_file);
+							else
+								fprintf(f,"#include \"%s\"\n", incl->included_file);
+							incl->output = 1;
+						}
+					}
+				}
+                
+				for (cmt = var->precomments; cmt; cmt=cmt->next) {
 					if (cmt->cmt[0] != ';' || cmt->cmt[1] != '!')
 						fprintf(f,"%s", cmt->cmt);
 				}
@@ -3841,13 +4101,12 @@
 					while (blanklines--)
 						fprintf(f, "\n");
 				}
-					
+				
+				fclose(f);
+                
+				
 				var = var->next;
 			}
-#if 0
-			/* Put an empty line */
-			fprintf(f, "\n");
-#endif
 			cat = cat->next;
 		}
 		if ((option_verbose > 1) && !option_debug)
@@ -3859,7 +4118,31 @@
 			ast_verbose(VERBOSE_PREFIX_2 "Unable to write (%s)", strerror(errno));
 		return -1;
 	}
-	fclose(f);
+
+	/* Now, for files with trailing #include/#exec statements,
+	   we have to make sure every entry is output */
+	
+	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);
+			f = fopen(fn, "a");
+			if (!f)
+			{
+				ast_verbose(VERBOSE_PREFIX_2 "Unable to write %s (%s)", fn, strerror(errno));
+				return -1;
+			}
+            
+			/* output the respective include */
+			if (incl->exec)
+				fprintf(f,"#exec \"%s\"\n", incl->exec_file);
+			else
+				fprintf(f,"#include \"%s\"\n", incl->included_file);
+			fclose(f);
+			incl->output = 1;
+		}
+	}
+	
 	return 0;
 }
 




More information about the asterisk-commits mailing list