mirror of
https://github.com/asterisk/asterisk.git
synced 2025-11-19 08:11:21 +00:00
aco: Create ways to minimize use of regex.
ACO uses regex in many situations where it is completely unneeded. In some cases this doubles the total processing performed by aco_process_config. * Create ACO_IGNORE category type for use in place of skip_category regex source string. * Create additional aco_category_op values to allow specifying category filter using either a single plain string or a NULL terminated array of plain strings. * Create ACO_PREFIX to allow matching option names to case insensitive prefixes. Change-Id: I66a920dcd8e2b0301f73f968016440a985e72821
This commit is contained in:
@@ -40,18 +40,30 @@ struct aco_type_internal;
|
|||||||
enum aco_type_t {
|
enum aco_type_t {
|
||||||
ACO_GLOBAL,
|
ACO_GLOBAL,
|
||||||
ACO_ITEM,
|
ACO_ITEM,
|
||||||
|
ACO_IGNORE,
|
||||||
};
|
};
|
||||||
|
|
||||||
/*! \brief Whether a category regex is a blackist or a whitelist */
|
/*! Type of category matching to perform */
|
||||||
enum aco_category_op {
|
enum aco_category_op {
|
||||||
|
/*! Regex based blacklist. */
|
||||||
ACO_BLACKLIST = 0,
|
ACO_BLACKLIST = 0,
|
||||||
|
/*! Regex based whitelist. */
|
||||||
ACO_WHITELIST,
|
ACO_WHITELIST,
|
||||||
|
/*! Blacklist with a single string matched with strcasecmp. */
|
||||||
|
ACO_BLACKLIST_EXACT,
|
||||||
|
/*! Whitelist with a single string matched with strcasecmp. */
|
||||||
|
ACO_WHITELIST_EXACT,
|
||||||
|
/*! Blacklist with a NULL terminated array of strings matched with strcasecmp. */
|
||||||
|
ACO_BLACKLIST_ARRAY,
|
||||||
|
/*! Whitelist with a NULL terminated array of strings matched with strcasecmp. */
|
||||||
|
ACO_WHITELIST_ARRAY,
|
||||||
};
|
};
|
||||||
|
|
||||||
/*! \brief What kind of matching should be done on an option name */
|
/*! \brief What kind of matching should be done on an option name */
|
||||||
enum aco_matchtype {
|
enum aco_matchtype {
|
||||||
ACO_EXACT = 1,
|
ACO_EXACT = 1,
|
||||||
ACO_REGEX,
|
ACO_REGEX,
|
||||||
|
ACO_PREFIX,
|
||||||
};
|
};
|
||||||
|
|
||||||
/*! Callback functions for option parsing via aco_process_config() */
|
/*! Callback functions for option parsing via aco_process_config() */
|
||||||
|
|||||||
@@ -131,7 +131,7 @@ static int noop_handler_fn(const struct aco_option *opt, struct ast_variable *va
|
|||||||
static int chararray_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj);
|
static int chararray_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj);
|
||||||
|
|
||||||
#ifdef AST_XML_DOCS
|
#ifdef AST_XML_DOCS
|
||||||
static int xmldoc_update_config_type(const char *module, const char *name, const char *category, const char *matchfield, const char *matchvalue, unsigned int matches);
|
static int xmldoc_update_config_type(const char *module, const char *name, const char *category, const char *matchfield, const char *matchvalue, enum aco_category_op category_match);
|
||||||
static int xmldoc_update_config_option(struct aco_type **types, const char *module, const char *name, const char *object_name, const char *default_value, unsigned int regex, enum aco_option_type type);
|
static int xmldoc_update_config_option(struct aco_type **types, const char *module, const char *name, const char *object_name, const char *default_value, unsigned int regex, enum aco_option_type type);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -373,6 +373,8 @@ static int find_option_cb(void *obj, void *arg, int flags)
|
|||||||
switch (match->match_type) {
|
switch (match->match_type) {
|
||||||
case ACO_EXACT:
|
case ACO_EXACT:
|
||||||
return strcasecmp(name, match->name) ? 0 : CMP_MATCH | CMP_STOP;
|
return strcasecmp(name, match->name) ? 0 : CMP_MATCH | CMP_STOP;
|
||||||
|
case ACO_PREFIX:
|
||||||
|
return strncasecmp(name, match->name, strlen(match->name)) ? 0 : CMP_MATCH | CMP_STOP;
|
||||||
case ACO_REGEX:
|
case ACO_REGEX:
|
||||||
return regexec(match->name_regex, name, 0, NULL, 0) ? 0 : CMP_MATCH | CMP_STOP;
|
return regexec(match->name_regex, name, 0, NULL, 0) ? 0 : CMP_MATCH | CMP_STOP;
|
||||||
}
|
}
|
||||||
@@ -402,6 +404,45 @@ struct ao2_container *aco_option_container_alloc(void)
|
|||||||
return ao2_container_alloc(CONFIG_OPT_BUCKETS, config_opt_hash, config_opt_cmp);
|
return ao2_container_alloc(CONFIG_OPT_BUCKETS, config_opt_hash, config_opt_cmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int internal_aco_type_category_check(struct aco_type *match, const char *category)
|
||||||
|
{
|
||||||
|
const char **categories = (const char **)match->category;
|
||||||
|
|
||||||
|
switch (match->category_match) {
|
||||||
|
case ACO_WHITELIST:
|
||||||
|
return regexec(match->internal->regex, category, 0, NULL, 0);
|
||||||
|
|
||||||
|
case ACO_BLACKLIST:
|
||||||
|
return !regexec(match->internal->regex, category, 0, NULL, 0);
|
||||||
|
|
||||||
|
case ACO_WHITELIST_EXACT:
|
||||||
|
return strcasecmp(match->category, category);
|
||||||
|
|
||||||
|
case ACO_BLACKLIST_EXACT:
|
||||||
|
return !strcasecmp(match->category, category);
|
||||||
|
|
||||||
|
case ACO_WHITELIST_ARRAY:
|
||||||
|
while (*categories) {
|
||||||
|
if (!strcasecmp(*categories, category)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
categories++;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
case ACO_BLACKLIST_ARRAY:
|
||||||
|
while (*categories) {
|
||||||
|
if (!strcasecmp(*categories, category)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
categories++;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
static struct aco_type *internal_aco_type_find(struct aco_file *file, struct ast_config *cfg, const char *category)
|
static struct aco_type *internal_aco_type_find(struct aco_file *file, struct ast_config *cfg, const char *category)
|
||||||
{
|
{
|
||||||
size_t x;
|
size_t x;
|
||||||
@@ -410,7 +451,7 @@ static struct aco_type *internal_aco_type_find(struct aco_file *file, struct ast
|
|||||||
|
|
||||||
for (x = 0, match = file->types[x]; match; match = file->types[++x]) {
|
for (x = 0, match = file->types[x]; match; match = file->types[++x]) {
|
||||||
/* First make sure we are an object that can service this category */
|
/* First make sure we are an object that can service this category */
|
||||||
if (!regexec(match->internal->regex, category, 0, NULL, 0) == !match->category_match) {
|
if (internal_aco_type_category_check(match, category)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -483,6 +524,10 @@ static int process_category(struct ast_config *cfg, struct aco_info *info, struc
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (type->type == ACO_IGNORE) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
field = info->internal->pending + type->item_offset;
|
field = info->internal->pending + type->item_offset;
|
||||||
if (!*field) {
|
if (!*field) {
|
||||||
ast_log(LOG_ERROR, "In %s: %s - No object to update!\n", file->filename, cat);
|
ast_log(LOG_ERROR, "In %s: %s - No object to update!\n", file->filename, cat);
|
||||||
@@ -631,6 +676,10 @@ enum aco_process_status aco_process_config(struct aco_info *info, int reload)
|
|||||||
for (i = 0, match = file->types[i]; match; match = file->types[++i]) {
|
for (i = 0, match = file->types[i]; match; match = file->types[++i]) {
|
||||||
void **field = info->internal->pending + match->item_offset;
|
void **field = info->internal->pending + match->item_offset;
|
||||||
|
|
||||||
|
if (match->type == ACO_IGNORE) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (match->type != ACO_GLOBAL || !*field) {
|
if (match->type != ACO_GLOBAL || !*field) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -797,9 +846,19 @@ static int internal_type_init(struct aco_type *type)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(type->internal->regex = build_regex(type->category))) {
|
switch (type->category_match) {
|
||||||
internal_type_destroy(type);
|
case ACO_BLACKLIST:
|
||||||
return -1;
|
case ACO_WHITELIST:
|
||||||
|
if (!(type->internal->regex = build_regex(type->category))) {
|
||||||
|
internal_type_destroy(type);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ACO_BLACKLIST_EXACT:
|
||||||
|
case ACO_WHITELIST_EXACT:
|
||||||
|
case ACO_BLACKLIST_ARRAY:
|
||||||
|
case ACO_WHITELIST_ARRAY:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(type->internal->opts = aco_option_container_alloc())) {
|
if (!(type->internal->opts = aco_option_container_alloc())) {
|
||||||
@@ -828,7 +887,8 @@ int aco_info_init(struct aco_info *info)
|
|||||||
#ifdef AST_XML_DOCS
|
#ifdef AST_XML_DOCS
|
||||||
if (!info->hidden &&
|
if (!info->hidden &&
|
||||||
!type->hidden &&
|
!type->hidden &&
|
||||||
xmldoc_update_config_type(info->module, type->name, type->category, type->matchfield, type->matchvalue, type->category_match == ACO_WHITELIST)) {
|
type->type != ACO_IGNORE &&
|
||||||
|
xmldoc_update_config_type(info->module, type->name, type->category, type->matchfield, type->matchvalue, type->category_match)) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
#endif /* AST_XML_DOCS */
|
#endif /* AST_XML_DOCS */
|
||||||
@@ -989,7 +1049,7 @@ static char *complete_config_option(const char *module, const char *option, cons
|
|||||||
/*! \internal
|
/*! \internal
|
||||||
* \brief Update the XML documentation for a config type based on its registration
|
* \brief Update the XML documentation for a config type based on its registration
|
||||||
*/
|
*/
|
||||||
static int xmldoc_update_config_type(const char *module, const char *name, const char *category, const char *matchfield, const char *matchvalue, unsigned int matches)
|
static int xmldoc_update_config_type(const char *module, const char *name, const char *category, const char *matchfield, const char *matchvalue, enum aco_category_op category_match)
|
||||||
{
|
{
|
||||||
RAII_VAR(struct ast_xml_xpath_results *, results, NULL, ast_xml_xpath_results_free);
|
RAII_VAR(struct ast_xml_xpath_results *, results, NULL, ast_xml_xpath_results_free);
|
||||||
RAII_VAR(struct ast_xml_doc_item *, config_info, ao2_find(xmldocs, module, OBJ_KEY), ao2_cleanup);
|
RAII_VAR(struct ast_xml_doc_item *, config_info, ao2_find(xmldocs, module, OBJ_KEY), ao2_cleanup);
|
||||||
@@ -1028,7 +1088,18 @@ static int xmldoc_update_config_type(const char *module, const char *name, const
|
|||||||
}
|
}
|
||||||
|
|
||||||
ast_xml_set_text(tmp, category);
|
ast_xml_set_text(tmp, category);
|
||||||
ast_xml_set_attribute(tmp, "match", matches ? "true" : "false");
|
switch (category_match) {
|
||||||
|
case ACO_WHITELIST:
|
||||||
|
case ACO_WHITELIST_EXACT:
|
||||||
|
case ACO_WHITELIST_ARRAY:
|
||||||
|
ast_xml_set_attribute(tmp, "match", "true");
|
||||||
|
break;
|
||||||
|
case ACO_BLACKLIST:
|
||||||
|
case ACO_BLACKLIST_EXACT:
|
||||||
|
case ACO_BLACKLIST_ARRAY:
|
||||||
|
ast_xml_set_attribute(tmp, "match", "false");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (!ast_strlen_zero(matchfield) && !(tmp = ast_xml_new_child(matchinfo, "field"))) {
|
if (!ast_strlen_zero(matchfield) && !(tmp = ast_xml_new_child(matchinfo, "field"))) {
|
||||||
ast_log(LOG_WARNING, "Could not add %s attribute for type '%s' in module '%s'\n", matchfield, name, module);
|
ast_log(LOG_WARNING, "Could not add %s attribute for type '%s' in module '%s'\n", matchfield, name, module);
|
||||||
|
|||||||
Reference in New Issue
Block a user