📄 astconfig.c
字号:
/*
* Asterisk -- An open source telephony toolkit.
*
* Copyright (C) 1999 - 2005, Digium, Inc.
*
* Mark Spencer <markster@digium.com>
*
* See http://www.asterisk.org for more information about
* the Asterisk project. Please do not directly contact
* any of the maintainers of this project for assistance;
* the project provides a web site, mailing lists and IRC
* channels for your use.
*
* This program is free software, distributed under the terms of
* the GNU General Public License Version 2. See the LICENSE file
* at the top of the source tree.
*/
/*! \file
*
* \brief Configuration File Parser
*
* \author Mark Spencer <markster@digium.com>
*
* Includes the Asterisk Realtime API - ARA
* See doc/realtime.txt and doc/extconfig.txt
*/
#include <asterisk.h>
ASTERISK_FILE_VERSION(__FILE__, "$Revision: 69470 $")
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <time.h>
#include <sys/stat.h>
#define AST_INCLUDE_GLOB 1
#ifdef AST_INCLUDE_GLOB
#if defined(__Darwin__) || defined(__CYGWIN__)
#define GLOB_ABORTED GLOB_ABEND
#endif
# include <glob.h>
#endif
#include "asterisk/config.h"
#include "asterisk/cli.h"
#include "asterisk/lock.h"
#include "asterisk/options.h"
#include "asterisk/logger.h"
#include "asterisk/utils.h"
#include "asterisk/channel.h"
#include "asterisk/app.h"
#include "astversion.h"
#define MAX_NESTED_COMMENTS 128
#define COMMENT_START ";--"
#define COMMENT_END "--;"
#define COMMENT_META ';'
#define COMMENT_TAG '-'
static char *extconfig_conf = "extconfig.conf";
#ifndef USE_ASTERISK_1_4
int ast_opt_exec_includes = 0;
#undef ast_malloc
#undef ast_realloc
#undef ast_calloc
#define ast_malloc malloc
#define ast_realloc realloc
#define ast_calloc calloc
#endif
/*! \brief Structure to keep comments for rewriting configuration files */
struct ast_comment {
struct ast_comment *next;
char cmt[0];
};
#define CB_INCR 250
static void CB_INIT(char **comment_buffer, int *comment_buffer_size, char **lline_buffer, int *lline_buffer_size)
{
if (!(*comment_buffer)) {
*comment_buffer = ast_malloc(CB_INCR);
if (!(*comment_buffer))
return;
(*comment_buffer)[0] = 0;
*comment_buffer_size = CB_INCR;
*lline_buffer = ast_malloc(CB_INCR);
if (!(*lline_buffer))
return;
(*lline_buffer)[0] = 0;
*lline_buffer_size = CB_INCR;
} else {
(*comment_buffer)[0] = 0;
(*lline_buffer)[0] = 0;
}
}
static void CB_ADD(char **comment_buffer, int *comment_buffer_size, char *str)
{
int rem = *comment_buffer_size - strlen(*comment_buffer) - 1;
int siz = strlen(str);
if (rem < siz+1) {
*comment_buffer = ast_realloc(*comment_buffer, *comment_buffer_size + CB_INCR + siz + 1);
if (!(*comment_buffer))
return;
*comment_buffer_size += CB_INCR+siz+1;
}
strcat(*comment_buffer,str);
}
static void CB_ADD_LEN(char **comment_buffer, int *comment_buffer_size, char *str, int len)
{
int cbl = strlen(*comment_buffer) + 1;
int rem = *comment_buffer_size - cbl;
if (rem < len+1) {
*comment_buffer = ast_realloc(*comment_buffer, *comment_buffer_size + CB_INCR + len + 1);
if (!(*comment_buffer))
return;
*comment_buffer_size += CB_INCR+len+1;
}
strncat(*comment_buffer,str,len);
(*comment_buffer)[cbl+len-1] = 0;
}
static void LLB_ADD(char **lline_buffer, int *lline_buffer_size, char *str)
{
int rem = *lline_buffer_size - strlen(*lline_buffer) - 1;
int siz = strlen(str);
if (rem < siz+1) {
*lline_buffer = ast_realloc(*lline_buffer, *lline_buffer_size + CB_INCR + siz + 1);
if (!(*lline_buffer))
return;
*lline_buffer_size += CB_INCR + siz + 1;
}
strcat(*lline_buffer,str);
}
static void CB_RESET(char **comment_buffer, char **lline_buffer)
{
(*comment_buffer)[0] = 0;
(*lline_buffer)[0] = 0;
}
static struct ast_comment *ALLOC_COMMENT(const char *buffer)
{
struct ast_comment *x = ast_calloc(1,sizeof(struct ast_comment)+strlen(buffer)+1);
strcpy(x->cmt, buffer);
return x;
}
static struct ast_config_map {
struct ast_config_map *next;
char *name;
char *driver;
char *database;
char *table;
char stuff[0];
} *config_maps = NULL;
AST_MUTEX_DEFINE_STATIC(config_lock);
static struct ast_config_engine *config_engine_list;
#define MAX_INCLUDE_LEVEL 10
struct ast_category {
char name[80];
int ignored; /*!< do not let user of the config see this category */
int include_level;
struct ast_comment *precomments;
struct ast_comment *sameline;
struct ast_variable *root;
struct ast_variable *last;
struct ast_category *next;
};
struct ast_config {
struct ast_category *root;
struct ast_category *last;
struct ast_category *current;
struct ast_category *last_browse; /*!< used to cache the last category supplied via category_browse */
int include_level;
int max_include_level;
};
struct ast_variable *ast_variable_new(const char *name, const char *value)
{
struct ast_variable *variable;
int name_len = strlen(name) + 1;
if ((variable = ast_calloc(1, name_len + strlen(value) + 1 + sizeof(*variable)))) {
variable->name = variable->stuff;
variable->value = variable->stuff + name_len;
strcpy(variable->name,name);
strcpy(variable->value,value);
}
return variable;
}
void ast_variable_append(struct ast_category *category, struct ast_variable *variable)
{
if (!variable)
return;
if (category->last)
category->last->next = variable;
else
category->root = variable;
category->last = variable;
while (category->last->next)
category->last = category->last->next;
}
void ast_variables_destroy(struct ast_variable *v)
{
struct ast_variable *vn;
while(v) {
vn = v;
v = v->next;
free(vn);
}
}
struct ast_variable *ast_variable_browse(const struct ast_config *config, const char *category)
{
struct ast_category *cat = NULL;
if (category && config->last_browse && (config->last_browse->name == category))
cat = config->last_browse;
else
cat = ast_category_get(config, category);
return (cat) ? cat->root : NULL;
}
const char *ast_config_option(struct ast_config *cfg, const char *cat, const char *var)
{
const char *tmp;
tmp = ast_variable_retrieve(cfg, cat, var);
if (!tmp)
tmp = ast_variable_retrieve(cfg, "general", var);
return tmp;
}
#ifdef USE_ASTERISK_1_4
const char *ast_variable_retrieve(const struct ast_config *config, const char *category, const char *variable)
#else
char *ast_variable_retrieve(const struct ast_config *config, const char *category, const char *variable)
#endif
{
struct ast_variable *v;
if (category) {
for (v = ast_variable_browse(config, category); v; v = v->next) {
if (!strcasecmp(variable, v->name))
return v->value;
}
} else {
struct ast_category *cat;
for (cat = config->root; cat; cat = cat->next)
for (v = cat->root; v; v = v->next)
if (!strcasecmp(variable, v->name))
return v->value;
}
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 = old->root;
old->root = NULL;
#if 1
/* we can just move the entire list in a single op */
ast_variable_append(new, var);
#else
while (var) {
struct ast_variable *next = var->next;
var->next = NULL;
ast_variable_append(new, var);
var = next;
}
#endif
}
struct ast_category *ast_category_new(const char *name)
{
struct ast_category *category;
if ((category = ast_calloc(1, sizeof(*category))))
ast_copy_string(category->name, name, sizeof(category->name));
return category;
}
static struct ast_category *category_get(const struct ast_config *config, const char *category_name, int ignored)
{
struct ast_category *cat;
/* try exact match first, then case-insensitive match */
for (cat = config->root; cat; cat = cat->next) {
if (cat->name == category_name && (ignored || !cat->ignored))
return cat;
}
for (cat = config->root; cat; cat = cat->next) {
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);
}
void ast_category_append(struct ast_config *config, struct ast_category *category)
{
if (config->last)
config->last->next = category;
else
config->root = category;
category->include_level = config->include_level;
config->last = category;
config->current = category;
}
void ast_category_destroy(struct ast_category *cat)
{
ast_variables_destroy(cat->root);
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;
if (prev && config->last_browse && (config->last_browse->name == prev))
cat = config->last_browse->next;
else if (!prev && config->root)
cat = config->root;
else if (prev) {
for (cat = config->root; cat; cat = cat->next) {
if (cat->name == prev) {
cat = cat->next;
break;
}
}
if (!cat) {
for (cat = config->root; cat; cat = cat->next) {
if (!strcasecmp(cat->name, prev)) {
cat = cat->next;
break;
}
}
}
}
if (cat)
cat = next_available_category(cat);
config->last_browse = cat;
return (cat) ? cat->name : NULL;
}
struct ast_variable *ast_category_detach_variables(struct ast_category *cat)
{
struct ast_variable *v;
v = cat->root;
cat->root = NULL;
cat->last = NULL;
return v;
}
void ast_category_rename(struct ast_category *cat, const char *name)
{
ast_copy_string(cat->name, name, sizeof(cat->name));
}
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)
ast_variable_append(new, variable_clone(var));
}
struct ast_config *ast_config_new(void)
{
struct ast_config *config;
if ((config = ast_calloc(1, sizeof(*config))))
config->max_include_level = MAX_INCLUDE_LEVEL;
return config;
}
#ifdef USE_ASTERISK_1_4
int ast_variable_delete(struct ast_category *category, char *variable, char *match)
{
struct ast_variable *cur, *prev=NULL, *curn;
int res = -1;
cur = category->root;
while (cur) {
if (cur->name == variable) {
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;
}
cur->next = NULL;
ast_variables_destroy(cur);
return 0;
}
prev = cur;
cur = cur->next;
}
prev = NULL;
cur = category->root;
while (cur) {
curn = cur->next;
if (!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;
}
cur->next = NULL;
ast_variables_destroy(cur);
res = 0;
} else
prev = cur;
cur = curn;
}
return res;
}
#endif
int ast_variable_update(struct ast_category *category, const char *variable,
const char *value, const char *match, unsigned int object)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -