Newer
Older
}
for (cat = config->root; cat; cat = cat->next) {
if (does_category_match(cat, category_name, filter, sep)) {
}
struct ast_category *ast_category_get(const struct ast_config *config,
const char *category_name, const char *filter)
{
return category_get_sep(config, category_name, filter, ',', 1);
const char *ast_category_get_name(const struct ast_category *category)
{
return category->name;
}
int ast_category_is_template(const struct ast_category *category)
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
return category->ignored;
}
struct ast_str *ast_category_get_templates(const struct ast_category *category)
{
struct ast_category_template_instance *template;
struct ast_str *str;
int first = 1;
if (AST_LIST_EMPTY(&category->template_instances)) {
return NULL;
}
str = ast_str_create(128);
if (!str) {
return NULL;
}
AST_LIST_TRAVERSE(&category->template_instances, template, next) {
ast_str_append(&str, 0, "%s%s", first ? "" : ",", template->name);
first = 0;
}
return str;
int ast_category_exist(const struct ast_config *config, const char *category_name,
const char *filter)
return !!ast_category_get(config, category_name, filter);
void ast_category_append(struct ast_config *config, struct ast_category *category)
{
if (config->last) {
category->prev = config->last;
} else {
category->prev = NULL;
}
category->next = NULL;
category->include_level = config->include_level;
config->last = category;
config->current = category;
}
George Joseph
committed
int ast_category_insert(struct ast_config *config, struct ast_category *cat, const char *match)
{
struct ast_category *cur_category;
if (!config || !config->root || !cat || !match) {
George Joseph
committed
return -1;
}
if (!strcasecmp(config->root->name, match)) {
cat->next = config->root;
cat->prev = NULL;
config->root->prev = cat;
George Joseph
committed
return 0;
for (cur_category = config->root->next; cur_category; cur_category = cur_category->next) {
if (!strcasecmp(cur_category->name, match)) {
cat->prev = cur_category->prev;
cat->prev->next = cat;
cat->next = cur_category;
cur_category->prev = cat;
George Joseph
committed
return 0;
George Joseph
committed
return -1;
static void ast_destroy_template_list(struct ast_category *cat)
{
struct ast_category_template_instance *x;
while ((x = AST_LIST_REMOVE_HEAD(&cat->template_instances, next)))
void ast_category_destroy(struct ast_category *cat)
cat->root = NULL;
cat->last = NULL;
ast_comment_destroy(&cat->precomments);
ast_comment_destroy(&cat->sameline);
ast_comment_destroy(&cat->trailing);
ast_destroy_template_list(cat);
Tilghman Lesher
committed
ast_free(cat);
Steve Murphy
committed
static void ast_includes_destroy(struct ast_config_include *incls)
{
struct ast_config_include *incl,*inclnext;
Steve Murphy
committed
for (incl=incls; incl; incl = inclnext) {
inclnext = incl->next;
ast_free(incl->include_location_file);
ast_free(incl->exec_file);
ast_free(incl->included_file);
ast_free(incl);
Steve Murphy
committed
}
}
static struct ast_category *next_available_category(struct ast_category *cat,
const char *name, const char *filter)
for (; cat && !does_category_match(cat, name, filter, ','); cat = cat->next);
/*! return the first var of a category */
struct ast_variable *ast_category_first(struct ast_category *cat)
{
return (cat) ? cat->root : NULL;
}
struct ast_variable *ast_category_root(struct ast_config *config, char *cat)
{
struct ast_category *category = ast_category_get(config, cat, NULL);
if (category)
return category->root;
return NULL;
}
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
void ast_config_sort_categories(struct ast_config *config, int descending,
int (*comparator)(struct ast_category *p, struct ast_category *q))
{
/*
* The contents of this function are adapted from
* an example of linked list merge sorting
* copyright 2001 Simon Tatham.
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL SIMON TATHAM BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
int insize = 1;
struct ast_category *p, *q, *e, *tail;
int nmerges, psize, qsize, i;
/* If the descending flag was sent, we'll apply inversion to the comparison function's return. */
if (descending) {
descending = -1;
} else {
descending = 1;
}
if (!config->root) {
return;
}
while (1) {
p = config->root;
config->root = NULL;
tail = NULL;
nmerges = 0; /* count number of merges we do in this pass */
while (p) {
nmerges++; /* there exists a merge to be done */
/* step `insize' places along from p */
q = p;
psize = 0;
for (i = 0; i < insize; i++) {
psize++;
q = q->next;
if (!q) {
break;
}
}
/* if q hasn't fallen off end, we have two lists to merge */
qsize = insize;
/* now we have two lists; merge them */
while (psize > 0 || (qsize > 0 && q)) {
/* decide whether next element of merge comes from p or q */
if (psize == 0) {
/* p is empty; e must come from q. */
e = q;
q = q->next;
qsize--;
} else if (qsize == 0 || !q) {
/* q is empty; e must come from p. */
e = p; p = p->next; psize--;
} else if ((comparator(p,q) * descending) <= 0) {
/* First element of p is lower (or same) e must come from p. */
e = p;
p = p->next;
psize--;
} else {
/* First element of q is lower; e must come from q. */
e = q;
q = q->next;
qsize--;
}
/* add the next element to the merged list */
if (tail) {
tail->next = e;
} else {
config->root = e;
}
tail = e;
}
/* now p has stepped `insize' places along, and q has too */
p = q;
}
tail->next = NULL;
/* If we have done only one merge, we're finished. */
if (nmerges <= 1) { /* allow for nmerges==0, the empty list case */
return;
}
/* Otherwise repeat, merging lists twice the size */
insize *= 2;
}
}
char *ast_category_browse(struct ast_config *config, const char *prev)
if (!prev) {
/* First time browse. */
cat = config->root;
} else if (config->last_browse && (config->last_browse->name == prev)) {
/* Simple last browse found. */
cat = config->last_browse->next;
} else {
/*
* Config changed since last browse.
*
* First try cheap last browse search. (Rebrowsing a different
* previous category?)
*/
for (cat = config->root; cat; cat = cat->next) {
if (cat->name == prev) {
/*
* Have to do it the hard way. (Last category was deleted and
* re-added?)
*/
for (cat = config->root; cat; cat = cat->next) {
if (!strcasecmp(cat->name, prev)) {
cat = cat->next;
break;
}
}
cat = next_available_category(cat, NULL, NULL);
return (cat) ? cat->name : NULL;
struct ast_category *ast_category_browse_filtered(struct ast_config *config,
const char *category_name, struct ast_category *prev, const char *filter)
{
struct ast_category *cat;
if (!prev) {
prev = config->root;
} else {
prev = prev->next;
}
cat = next_available_category(prev, category_name, filter);
return cat;
}
struct ast_variable *ast_category_detach_variables(struct ast_category *cat)
struct ast_variable *v;
v = cat->root;
cat->root = NULL;
return v;
}
void ast_category_rename(struct ast_category *cat, const char *name)
{
ast_copy_string(cat->name, name, sizeof(cat->name));
int ast_category_inherit(struct ast_category *new, const struct ast_category *base)
struct ast_category_template_instance *x;
x = ast_calloc(1, sizeof(*x));
if (!x) {
strcpy(x->name, base->name);
x->inst = base;
AST_LIST_INSERT_TAIL(&new->template_instances, x, next);
George Joseph
committed
for (var = base->root; var; var = var->next) {
struct ast_variable *cloned = variable_clone(var);
if (!cloned) {
return -1;
}
George Joseph
committed
cloned->inherited = 1;
ast_variable_append(new, cloned);
}
struct ast_config *ast_config_new(void)
if ((config = ast_calloc(1, sizeof(*config))))
config->max_include_level = MAX_INCLUDE_LEVEL;
return config;
int ast_variable_delete(struct ast_category *category, const char *variable, const char *match, const char *line)
struct ast_variable *cur, *prev=NULL, *curn;
int res = -1;
int num_item = 0;
int req_item;
req_item = -1;
if (!ast_strlen_zero(line)) {
/* Requesting to delete by item number. */
if (sscanf(line, "%30d", &req_item) != 1
|| req_item < 0) {
/* Invalid item number to delete. */
return -1;
cur = category->root;
while (cur) {
curn = cur->next;
/* Delete by item number or by variable name with optional value. */
if ((0 <= req_item && num_item == req_item)
|| (req_item < 0 && !strcasecmp(cur->name, variable)
&& (ast_strlen_zero(match) || !strcasecmp(cur->value, match)))) {
if (prev) {
prev->next = cur->next;
if (cur == category->last)
category->last = prev;
} else {
category->root = cur->next;
if (cur == category->last)
category->last = NULL;
}
res = 0;
} else
prev = cur;
cur = curn;
return res;
int ast_variable_update(struct ast_category *category, const char *variable,
Steve Murphy
committed
const char *value, const char *match, unsigned int object)
struct ast_variable *cur, *prev=NULL, *newer=NULL;
for (cur = category->root; cur; prev = cur, cur = cur->next) {
if (strcasecmp(cur->name, variable) ||
(!ast_strlen_zero(match) && strcasecmp(cur->value, match)))
continue;
Steve Murphy
committed
if (!(newer = ast_variable_new(variable, value, cur->file)))
return -1;
ast_variable_move(newer, cur);
newer->object = newer->object || object;
/* Replace the old node in the list with the new node. */
newer->next = cur->next;
if (prev)
prev->next = newer;
else
category->root = newer;
if (category->last == cur)
category->last = newer;
/* Could not find variable to update */
return -1;
struct ast_category *ast_category_delete(struct ast_config *config,
struct ast_category *category)
struct ast_category *prev;
if (!config || !category) {
return NULL;
if (category->prev) {
category->prev->next = category->next;
} else {
config->root = category->next;
if (category->next) {
category->next->prev = category->prev;
} else {
config->last = category->prev;
}
prev = category->prev;
if (config->last_browse == category) {
config->last_browse = prev;
}
ast_category_destroy(category);
return prev;
int ast_category_empty(struct ast_category *category)
if (!category) {
return -1;
ast_variables_destroy(category->root);
category->root = NULL;
category->last = NULL;
return 0;
void ast_config_destroy(struct ast_config *cfg)
struct ast_category *cat, *catn;
if (!cfg)
return;
Steve Murphy
committed
ast_includes_destroy(cfg->includes);
Joshua Colp
committed
while (cat) {
Tilghman Lesher
committed
ast_free(cfg);
struct ast_category *ast_config_get_current_category(const struct ast_config *cfg)
Mark Spencer
committed
void ast_config_set_current_category(struct ast_config *cfg, const struct ast_category *cat)
/* cast below is just to silence compiler warning about dropping "const" */
cfg->current = (struct ast_category *) cat;
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
/*!
* \internal
* \brief Create a new cfmtime list node.
*
* \param filename Config filename caching.
* \param who_asked Who wanted to know.
*
* \retval cfmtime New node on success.
* \retval NULL on error.
*/
static struct cache_file_mtime *cfmtime_new(const char *filename, const char *who_asked)
{
struct cache_file_mtime *cfmtime;
char *dst;
cfmtime = ast_calloc(1,
sizeof(*cfmtime) + strlen(filename) + 1 + strlen(who_asked) + 1);
if (!cfmtime) {
return NULL;
}
dst = cfmtime->filename; /* writable space starts here */
Richard Mudgett
committed
strcpy(dst, filename); /* Safe */
Richard Mudgett
committed
cfmtime->who_asked = strcpy(dst, who_asked); /* Safe */
return cfmtime;
}
enum config_cache_attribute_enum {
ATTRIBUTE_INCLUDE = 0,
ATTRIBUTE_EXEC = 1,
};
Richard Mudgett
committed
/*!
* \internal
* \brief Save the stat() data to the cached file modtime struct.
*
* \param cfmtime Cached file modtime.
* \param statbuf Buffer filled in by stat().
*
* \return Nothing
*/
static void cfmstat_save(struct cache_file_mtime *cfmtime, struct stat *statbuf)
{
cfmtime->stat_size = statbuf->st_size;
#if defined(HAVE_STRUCT_STAT_ST_MTIM)
Richard Mudgett
committed
cfmtime->stat_mtime_nsec = statbuf->st_mtim.tv_nsec;
#elif defined(HAVE_STRUCT_STAT_ST_MTIMENSEC)
Richard Mudgett
committed
cfmtime->stat_mtime_nsec = statbuf->st_mtimensec;
#elif defined(HAVE_STRUCT_STAT_ST_MTIMESPEC)
cfmtime->stat_mtime_nsec = statbuf->st_mtimespec.tv_nsec;
#else
cfmtime->stat_mtime_nsec = 0;
Richard Mudgett
committed
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
#endif
cfmtime->stat_mtime = statbuf->st_mtime;
}
/*!
* \internal
* \brief Compare the stat() data with the cached file modtime struct.
*
* \param cfmtime Cached file modtime.
* \param statbuf Buffer filled in by stat().
*
* \retval non-zero if different.
*/
static int cfmstat_cmp(struct cache_file_mtime *cfmtime, struct stat *statbuf)
{
struct cache_file_mtime cfm_buf;
cfmstat_save(&cfm_buf, statbuf);
return cfmtime->stat_size != cfm_buf.stat_size
|| cfmtime->stat_mtime != cfm_buf.stat_mtime
|| cfmtime->stat_mtime_nsec != cfm_buf.stat_mtime_nsec;
}
Richard Mudgett
committed
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
/*!
* \internal
* \brief Clear the cached file modtime include list.
*
* \param cfmtime Cached file modtime.
*
* \note cfmtime_head is assumed already locked.
*
* \return Nothing
*/
static void config_cache_flush_includes(struct cache_file_mtime *cfmtime)
{
struct cache_file_include *cfinclude;
while ((cfinclude = AST_LIST_REMOVE_HEAD(&cfmtime->includes, list))) {
ast_free(cfinclude);
}
}
/*!
* \internal
* \brief Destroy the given cached file modtime entry.
*
* \param cfmtime Cached file modtime.
*
* \note cfmtime_head is assumed already locked.
*
* \return Nothing
*/
static void config_cache_destroy_entry(struct cache_file_mtime *cfmtime)
{
config_cache_flush_includes(cfmtime);
ast_free(cfmtime);
}
/*!
* \internal
* \brief Remove and destroy the config cache entry for the filename and who_asked.
*
* \param filename Config filename.
* \param who_asked Which module asked.
*
* \return Nothing
*/
static void config_cache_remove(const char *filename, const char *who_asked)
{
struct cache_file_mtime *cfmtime;
AST_LIST_LOCK(&cfmtime_head);
AST_LIST_TRAVERSE_SAFE_BEGIN(&cfmtime_head, cfmtime, list) {
if (!strcmp(cfmtime->filename, filename)
&& !strcmp(cfmtime->who_asked, who_asked)) {
AST_LIST_REMOVE_CURRENT(list);
config_cache_destroy_entry(cfmtime);
break;
}
}
AST_LIST_TRAVERSE_SAFE_END;
AST_LIST_UNLOCK(&cfmtime_head);
}
Tilghman Lesher
committed
static void config_cache_attribute(const char *configfile, enum config_cache_attribute_enum attrtype, const char *filename, const char *who_asked)
{
struct cache_file_mtime *cfmtime;
struct cache_file_include *cfinclude;
/* Find our cached entry for this configuration file */
AST_LIST_LOCK(&cfmtime_head);
AST_LIST_TRAVERSE(&cfmtime_head, cfmtime, list) {
if (!strcmp(cfmtime->filename, configfile) && !strcmp(cfmtime->who_asked, who_asked))
break;
}
if (!cfmtime) {
cfmtime = cfmtime_new(configfile, who_asked);
if (!cfmtime) {
AST_LIST_UNLOCK(&cfmtime_head);
return;
}
/* Note that the file mtime is initialized to 0, i.e. 1970 */
AST_LIST_INSERT_SORTALPHA(&cfmtime_head, cfmtime, list, filename);
}
switch (attrtype) {
case ATTRIBUTE_INCLUDE:
AST_LIST_TRAVERSE(&cfmtime->includes, cfinclude, list) {
if (!strcmp(cfinclude->include, filename)) {
AST_LIST_UNLOCK(&cfmtime_head);
return;
}
}
cfinclude = ast_calloc(1, sizeof(*cfinclude) + strlen(filename) + 1);
if (!cfinclude) {
AST_LIST_UNLOCK(&cfmtime_head);
return;
}
Richard Mudgett
committed
strcpy(cfinclude->include, filename); /* Safe */
AST_LIST_INSERT_TAIL(&cfmtime->includes, cfinclude, list);
break;
case ATTRIBUTE_EXEC:
cfmtime->has_exec = 1;
break;
}
AST_LIST_UNLOCK(&cfmtime_head);
}
/*! \brief parse one line in the configuration.
* We can have a category header [foo](...)
* a directive #include / #exec
* or a regular line name = value
*/
static int process_text_line(struct ast_config *cfg, struct ast_category **cat,
char *buf, int lineno, const char *configfile, struct ast_flags flags,
struct ast_str *comment_buffer,
struct ast_str *lline_buffer,
const char *suggested_include_file,
Tilghman Lesher
committed
struct ast_category **last_cat, struct ast_variable **last_var, const char *who_asked)
char cmd[512], exec_file[512];
/* Actually parse the entry */
if (cur[0] == '[') { /* A category header */
/* format is one of the following:
* [foo] define a new category named 'foo'
* [foo](!) define a new template category named 'foo'
* [foo](+) append to category 'foo', error if foo does not exist.
* [foo](a) define a new category and inherit from category or template a.
* You can put a comma-separated list of categories and templates
* and '!' and '+' between parentheses, with obvious meaning.
struct ast_category *newcat;
c = strchr(cur, ']');
if (!c) {
ast_log(LOG_WARNING, "parse error: no closing ']', line %d of %s\n", lineno, configfile);
return -1;
}
*cat = newcat = ast_category_new(catname,
S_OR(suggested_include_file, cfg->include_level == 1 ? "" : configfile),
lineno);
if (!newcat) {
Steve Murphy
committed
(*cat)->lineno = lineno;
if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS))
newcat->precomments = ALLOC_COMMENT(comment_buffer);
if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS))
newcat->sameline = ALLOC_COMMENT(lline_buffer);
if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS))
CB_RESET(comment_buffer, lline_buffer);
/* 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 (cur[0] == '+') {
char *filter = NULL;
if (cur[1] != ',') {
filter = &cur[1];
}
*cat = category_get_sep(cfg, catname, filter, '&', 0);
if (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) {
ast_config_set_current_category(cfg, *cat);
(*cat)->ignored |= newcat->ignored;
move_variables(newcat, *cat);
ast_category_destroy(newcat);
newcat = NULL;
}
} else {
struct ast_category *base;
base = category_get_sep(cfg, cur, "TEMPLATES=include", ',', 0);
if (newcat) {
ast_category_destroy(newcat);
}
ast_log(LOG_WARNING, "Inheritance requested, but category '%s' does not exist, line %d of %s\n", cur, lineno, configfile);
return -1;
}
if (ast_category_inherit(*cat, base)) {
if (newcat) {
ast_category_destroy(newcat);
}
ast_log(LOG_ERROR, "Inheritence requested, but allocation failed\n");
return -1;
}
/*
* We need to set *last_cat to newcat here regardless. If the
* category is being appended to we have no place for trailing
* comments on the appended category. The appended category
* may be in another file or it already has trailing comments
* that we would then leak.
*/
*last_var = NULL;
*last_cat = newcat;
if (newcat) {
ast_category_append(cfg, newcat);
}
} else if (cur[0] == '#') { /* A directive - #include or #exec */
char *cur2;
char real_inclusion_name[256];
int do_include = 0; /* otherwise, it is exec */
Tilghman Lesher
committed
while (*c && (*c > 32)) {
c++;
}
if (*c) {
*c = '\0';
/* Find real argument */
c = ast_strip(c + 1);
Tilghman Lesher
committed
if (!(*c)) {
Tilghman Lesher
committed
}
if (!strcasecmp(cur, "include")) {
do_include = 1;
} else if (!strcasecmp(cur, "tryinclude")) {
do_include = 1;
try_include = 1;
} else if (!strcasecmp(cur, "exec")) {
if (!ast_opt_exec_includes) {
ast_log(LOG_WARNING, "Cannot perform #exec unless execincludes option is enabled in asterisk.conf (options section)!\n");
return 0; /* XXX is this correct ? or we should return -1 ? */
}
} else {
ast_log(LOG_WARNING, "Unknown directive '#%s' at line %d of %s\n", cur, lineno, configfile);
return 0; /* XXX is this correct ? or we should return -1 ? */
if (c == NULL) {
ast_log(LOG_WARNING, "Directive '#%s' needs an argument (%s) at line %d of %s\n",
do_include ? "include / tryinclude" : "exec",
do_include ? "filename" : "/path/to/executable",
lineno,
configfile);
return 0; /* XXX is this correct ? or we should return -1 ? */
}
/* Strip off leading and trailing "'s and <>'s */
/* Dequote */
if ((*c == '"') || (*c == '<')) {
char quote_char = *c;
if (quote_char == '<') {
quote_char = '>';
if (*(c + strlen(c) - 1) == quote_char) {
cur++;
*(c + strlen(c) - 1) = '\0';
}
/* #exec </path/to/executable>
We create a tmp file, then we #include it, then we delete it. */
if (!do_include) {
struct timeval now = ast_tvnow();
if (!ast_test_flag(&flags, CONFIG_FLAG_NOCACHE))
config_cache_attribute(configfile, ATTRIBUTE_EXEC, NULL, who_asked);
snprintf(exec_file, sizeof(exec_file), "/var/tmp/exec.%d%d.%ld", (int)now.tv_sec, (int)now.tv_usec, (long)pthread_self());
snprintf(cmd, sizeof(cmd), "%s > %s 2>&1", cur, exec_file);
ast_safe_system(cmd);
cur = exec_file;
} else {
if (!ast_test_flag(&flags, CONFIG_FLAG_NOCACHE))
config_cache_attribute(configfile, ATTRIBUTE_INCLUDE, cur, who_asked);
exec_file[0] = '\0';
}
/* A #include */
/* record this inclusion */
ast_include_new(cfg, cfg->include_level == 1 ? "" : configfile, cur, !do_include, cur2, lineno, real_inclusion_name, sizeof(real_inclusion_name));
do_include = ast_config_internal_load(cur, cfg, flags, real_inclusion_name, who_asked) ? 1 : 0;
if (!ast_strlen_zero(exec_file))
unlink(exec_file);
ast_log(LOG_ERROR, "The file '%s' was listed as a #include but it does not exist.\n", cur);
return -1;
}
/* XXX otherwise what ? the default return is 0 anyways */
} else {
/* Just a line (variable = value) */
int is_escaped;
ast_log(LOG_WARNING,
"parse error: No category context for line %d of %s\n", lineno, configfile);
return -1;
}
is_escaped = cur[0] == '\\';
if (is_escaped) {
/* First character is escaped. */
++cur;
if (cur[0] < 33) {
ast_log(LOG_ERROR, "Invalid escape in line %d of %s\n", lineno, configfile);
return -1;
}
}
c = strchr(cur + is_escaped, '=');
if (c && c > cur + is_escaped && (*(c - 1) == '+')) {
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
struct ast_variable *var, *replace = NULL;
struct ast_str **str = ast_threadstorage_get(&appendbuf, sizeof(*str));
if (!str || !*str) {
return -1;
}
*(c - 1) = '\0';
c++;
cur = ast_strip(cur);
/* Must iterate through category until we find last variable of same name (since there could be multiple) */
for (var = ast_category_first(*cat); var; var = var->next) {
if (!strcmp(var->name, cur)) {
replace = var;
}
}
if (!replace) {
/* Nothing to replace; just set a variable normally. */
goto set_new_variable;
}
ast_str_set(str, 0, "%s", replace->value);
ast_str_append(str, 0, "%s", c);
ast_str_trim_blanks(*str);
ast_variable_update(*cat, replace->name, ast_skip_blanks(ast_str_buffer(*str)), replace->value, object);
*c = 0;
c++;
/* Ignore > in => */
if (*c== '>') {
object = 1;
cur = ast_strip(cur);
if (ast_strlen_zero(cur)) {
ast_log(LOG_WARNING, "No variable name in line %d of %s\n", lineno, configfile);
} else if ((v = ast_variable_new(cur, ast_strip(c), S_OR(suggested_include_file, cfg->include_level == 1 ? "" : configfile)))) {