<p>Corey Farrell has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.asterisk.org/7564">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">aco: Create ways to minimize use of regex.<br><br>ACO uses regex in many situations where it is completely unneeded. In<br>some cases this doubles the total processing performed by<br>aco_process_config.<br><br>* Create ACO_IGNORE category type for use in place of skip_category<br> regex source string.<br>* Create additional aco_category_op values to allow specifying category<br> filter using either a single plain string or a NULL terminated array<br> of plain strings.<br>* Create ACO_PREFIX to allow matching option names to case insensitive<br> prefixes.<br><br>Change-Id: I66a920dcd8e2b0301f73f968016440a985e72821<br>---<br>M include/asterisk/config_options.h<br>M main/config_options.c<br>2 files changed, 90 insertions(+), 9 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.asterisk.org:29418/asterisk refs/changes/64/7564/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">diff --git a/include/asterisk/config_options.h b/include/asterisk/config_options.h<br>index f4c3db1..3227f94 100644<br>--- a/include/asterisk/config_options.h<br>+++ b/include/asterisk/config_options.h<br>@@ -40,18 +40,30 @@<br> enum aco_type_t {<br> ACO_GLOBAL,<br> ACO_ITEM,<br>+ ACO_IGNORE,<br> };<br> <br>-/*! \brief Whether a category regex is a blackist or a whitelist */<br>+/*! Type of category matching to perform */<br> enum aco_category_op {<br>+ /*! Regex based blacklist. */<br> ACO_BLACKLIST = 0,<br>+ /*! Regex based whitelist. */<br> ACO_WHITELIST,<br>+ /*! Blacklist with a single string matched with strcasecmp. */<br>+ ACO_BLACKLIST_EXACT,<br>+ /*! Whitelist with a single string matched with strcasecmp. */<br>+ ACO_WHITELIST_EXACT,<br>+ /*! Blacklist with a NULL terminated array of strings matched with strcasecmp. */<br>+ ACO_BLACKLIST_ARRAY,<br>+ /*! Whitelist with a NULL terminated array of strings matched with strcasecmp. */<br>+ ACO_WHITELIST_ARRAY,<br> };<br> <br> /*! \brief What kind of matching should be done on an option name */<br> enum aco_matchtype {<br> ACO_EXACT = 1,<br> ACO_REGEX,<br>+ ACO_PREFIX,<br> };<br> <br> /*! Callback functions for option parsing via aco_process_config() */<br>diff --git a/main/config_options.c b/main/config_options.c<br>index a9a145b..7c3e767 100644<br>--- a/main/config_options.c<br>+++ b/main/config_options.c<br>@@ -131,7 +131,7 @@<br> static int chararray_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj);<br> <br> #ifdef AST_XML_DOCS<br>-static int xmldoc_update_config_type(const char *module, const char *name, const char *category, const char *matchfield, const char *matchvalue, unsigned int matches);<br>+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);<br> 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);<br> #endif<br> <br>@@ -373,6 +373,8 @@<br> switch (match->match_type) {<br> case ACO_EXACT:<br> return strcasecmp(name, match->name) ? 0 : CMP_MATCH | CMP_STOP;<br>+ case ACO_PREFIX:<br>+ return strncasecmp(name, match->name, strlen(match->name)) ? 0 : CMP_MATCH | CMP_STOP;<br> case ACO_REGEX:<br> return regexec(match->name_regex, name, 0, NULL, 0) ? 0 : CMP_MATCH | CMP_STOP;<br> }<br>@@ -402,6 +404,43 @@<br> return ao2_container_alloc(CONFIG_OPT_BUCKETS, config_opt_hash, config_opt_cmp);<br> }<br> <br>+static int internal_aco_type_category_check(struct aco_type *match, const char *category)<br>+{<br>+ const char **categories = (const char **)match->category;<br>+<br>+ switch (match->category_match) {<br>+ case ACO_WHITELIST:<br>+ case ACO_BLACKLIST:<br>+ return !regexec(match->internal->regex, category, 0, NULL, 0) == !match->category_match;<br>+<br>+ case ACO_WHITELIST_EXACT:<br>+ return strcasecmp(match->category, category);<br>+<br>+ case ACO_BLACKLIST_EXACT:<br>+ return !strcasecmp(match->category, category);<br>+<br>+ case ACO_WHITELIST_ARRAY:<br>+ while (*categories) {<br>+ if (!strcasecmp(*categories, category)) {<br>+ return 0;<br>+ }<br>+ categories++;<br>+ }<br>+ return -1;<br>+<br>+ case ACO_BLACKLIST_ARRAY:<br>+ while (*categories) {<br>+ if (!strcasecmp(*categories, category)) {<br>+ return -1;<br>+ }<br>+ categories++;<br>+ }<br>+ return 0;<br>+ }<br>+<br>+ return -1;<br>+}<br>+<br> static struct aco_type *internal_aco_type_find(struct aco_file *file, struct ast_config *cfg, const char *category)<br> {<br> size_t x;<br>@@ -410,7 +449,7 @@<br> <br> for (x = 0, match = file->types[x]; match; match = file->types[++x]) {<br> /* First make sure we are an object that can service this category */<br>- if (!regexec(match->internal->regex, category, 0, NULL, 0) == !match->category_match) {<br>+ if (internal_aco_type_category_check(match, category)) {<br> continue;<br> }<br> <br>@@ -481,6 +520,10 @@<br> if (!(type = internal_aco_type_find(file, cfg, cat))) {<br> ast_log(LOG_ERROR, "Could not find config type for category '%s' in '%s'\n", cat, file->filename);<br> return -1;<br>+ }<br>+<br>+ if (type->type == ACO_IGNORE) {<br>+ return 0;<br> }<br> <br> field = info->internal->pending + type->item_offset;<br>@@ -630,6 +673,10 @@<br> /* set defaults for global objects */<br> for (i = 0, match = file->types[i]; match; match = file->types[++i]) {<br> void **field = info->internal->pending + match->item_offset;<br>+<br>+ if (match->type == ACO_IGNORE) {<br>+ continue;<br>+ }<br> <br> if (match->type != ACO_GLOBAL || !*field) {<br> continue;<br>@@ -797,9 +844,19 @@<br> return -1;<br> }<br> <br>- if (!(type->internal->regex = build_regex(type->category))) {<br>- internal_type_destroy(type);<br>- return -1;<br>+ switch (type->category_match) {<br>+ case ACO_BLACKLIST:<br>+ case ACO_WHITELIST:<br>+ if (!(type->internal->regex = build_regex(type->category))) {<br>+ internal_type_destroy(type);<br>+ return -1;<br>+ }<br>+ break;<br>+ case ACO_BLACKLIST_EXACT:<br>+ case ACO_WHITELIST_EXACT:<br>+ case ACO_BLACKLIST_ARRAY:<br>+ case ACO_WHITELIST_ARRAY:<br>+ break;<br> }<br> <br> if (!(type->internal->opts = aco_option_container_alloc())) {<br>@@ -828,7 +885,8 @@<br> #ifdef AST_XML_DOCS<br> if (!info->hidden &&<br> !type->hidden &&<br>- xmldoc_update_config_type(info->module, type->name, type->category, type->matchfield, type->matchvalue, type->category_match == ACO_WHITELIST)) {<br>+ type->type != ACO_IGNORE &&<br>+ xmldoc_update_config_type(info->module, type->name, type->category, type->matchfield, type->matchvalue, type->category_match)) {<br> goto error;<br> }<br> #endif /* AST_XML_DOCS */<br>@@ -989,7 +1047,7 @@<br> /*! \internal<br> * \brief Update the XML documentation for a config type based on its registration<br> */<br>-static int xmldoc_update_config_type(const char *module, const char *name, const char *category, const char *matchfield, const char *matchvalue, unsigned int matches)<br>+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)<br> {<br> RAII_VAR(struct ast_xml_xpath_results *, results, NULL, ast_xml_xpath_results_free);<br> RAII_VAR(struct ast_xml_doc_item *, config_info, ao2_find(xmldocs, module, OBJ_KEY), ao2_cleanup);<br>@@ -1028,7 +1086,18 @@<br> }<br> <br> ast_xml_set_text(tmp, category);<br>- ast_xml_set_attribute(tmp, "match", matches ? "true" : "false");<br>+ switch (category_match) {<br>+ case ACO_WHITELIST:<br>+ case ACO_WHITELIST_EXACT:<br>+ case ACO_WHITELIST_ARRAY:<br>+ ast_xml_set_attribute(tmp, "match", "true");<br>+ break;<br>+ case ACO_BLACKLIST:<br>+ case ACO_BLACKLIST_EXACT:<br>+ case ACO_BLACKLIST_ARRAY:<br>+ ast_xml_set_attribute(tmp, "match", "false");<br>+ break;<br>+ }<br> <br> if (!ast_strlen_zero(matchfield) && !(tmp = ast_xml_new_child(matchinfo, "field"))) {<br> ast_log(LOG_WARNING, "Could not add %s attribute for type '%s' in module '%s'\n", matchfield, name, module);<br></pre><p>To view, visit <a href="https://gerrit.asterisk.org/7564">change 7564</a>. To unsubscribe, visit <a href="https://gerrit.asterisk.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.asterisk.org/7564"/><meta itemprop="name" content="View Change"/></div></div>
<div style="display:none"> Gerrit-Project: asterisk </div>
<div style="display:none"> Gerrit-Branch: 15 </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>
<div style="display:none"> Gerrit-Change-Id: I66a920dcd8e2b0301f73f968016440a985e72821 </div>
<div style="display:none"> Gerrit-Change-Number: 7564 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: Corey Farrell <git@cfware.com> </div>