[Asterisk-code-review] aco: Create ways to minimize use of regex. (asterisk[15])
Corey Farrell
asteriskteam at digium.com
Wed Dec 13 12:38:55 CST 2017
Corey Farrell has uploaded this change for review. ( https://gerrit.asterisk.org/7564
Change subject: aco: Create ways to minimize use of regex.
......................................................................
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
---
M include/asterisk/config_options.h
M main/config_options.c
2 files changed, 90 insertions(+), 9 deletions(-)
git pull ssh://gerrit.asterisk.org:29418/asterisk refs/changes/64/7564/1
diff --git a/include/asterisk/config_options.h b/include/asterisk/config_options.h
index f4c3db1..3227f94 100644
--- a/include/asterisk/config_options.h
+++ b/include/asterisk/config_options.h
@@ -40,18 +40,30 @@
enum aco_type_t {
ACO_GLOBAL,
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 {
+ /*! Regex based blacklist. */
ACO_BLACKLIST = 0,
+ /*! Regex based 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 */
enum aco_matchtype {
ACO_EXACT = 1,
ACO_REGEX,
+ ACO_PREFIX,
};
/*! Callback functions for option parsing via aco_process_config() */
diff --git a/main/config_options.c b/main/config_options.c
index a9a145b..7c3e767 100644
--- a/main/config_options.c
+++ b/main/config_options.c
@@ -131,7 +131,7 @@
static int chararray_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj);
#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);
#endif
@@ -373,6 +373,8 @@
switch (match->match_type) {
case ACO_EXACT:
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:
return regexec(match->name_regex, name, 0, NULL, 0) ? 0 : CMP_MATCH | CMP_STOP;
}
@@ -402,6 +404,43 @@
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:
+ case ACO_BLACKLIST:
+ return !regexec(match->internal->regex, category, 0, NULL, 0) == !match->category_match;
+
+ 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)
{
size_t x;
@@ -410,7 +449,7 @@
for (x = 0, match = file->types[x]; match; match = file->types[++x]) {
/* 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;
}
@@ -481,6 +520,10 @@
if (!(type = internal_aco_type_find(file, cfg, cat))) {
ast_log(LOG_ERROR, "Could not find config type for category '%s' in '%s'\n", cat, file->filename);
return -1;
+ }
+
+ if (type->type == ACO_IGNORE) {
+ return 0;
}
field = info->internal->pending + type->item_offset;
@@ -630,6 +673,10 @@
/* set defaults for global objects */
for (i = 0, match = file->types[i]; match; match = file->types[++i]) {
void **field = info->internal->pending + match->item_offset;
+
+ if (match->type == ACO_IGNORE) {
+ continue;
+ }
if (match->type != ACO_GLOBAL || !*field) {
continue;
@@ -797,9 +844,19 @@
return -1;
}
- if (!(type->internal->regex = build_regex(type->category))) {
- internal_type_destroy(type);
- return -1;
+ switch (type->category_match) {
+ case ACO_BLACKLIST:
+ 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())) {
@@ -828,7 +885,8 @@
#ifdef AST_XML_DOCS
if (!info->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;
}
#endif /* AST_XML_DOCS */
@@ -989,7 +1047,7 @@
/*! \internal
* \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_doc_item *, config_info, ao2_find(xmldocs, module, OBJ_KEY), ao2_cleanup);
@@ -1028,7 +1086,18 @@
}
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"))) {
ast_log(LOG_WARNING, "Could not add %s attribute for type '%s' in module '%s'\n", matchfield, name, module);
--
To view, visit https://gerrit.asterisk.org/7564
To unsubscribe, visit https://gerrit.asterisk.org/settings
Gerrit-Project: asterisk
Gerrit-Branch: 15
Gerrit-MessageType: newchange
Gerrit-Change-Id: I66a920dcd8e2b0301f73f968016440a985e72821
Gerrit-Change-Number: 7564
Gerrit-PatchSet: 1
Gerrit-Owner: Corey Farrell <git at cfware.com>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.digium.com/pipermail/asterisk-code-review/attachments/20171213/4c087103/attachment-0001.html>
More information about the asterisk-code-review
mailing list