<p>Joshua Colp <strong>merged</strong> this change.</p><p><a href="https://gerrit.asterisk.org/7564">View Change</a></p><div style="white-space:pre-wrap">Approvals:
  George Joseph: Looks good to me, but someone else must approve
  Joshua Colp: Looks good to me, approved; Approved for Submit

</div><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, 92 insertions(+), 9 deletions(-)<br><br></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..1f4f99b 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,45 @@<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>+          return regexec(match->internal->regex, category, 0, NULL, 0);<br>+<br>+       case ACO_BLACKLIST:<br>+          return !regexec(match->internal->regex, category, 0, NULL, 0);<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 +451,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 +522,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 +675,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 +846,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 +887,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 +1049,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 +1088,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: merged </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: 2 </div>
<div style="display:none"> Gerrit-Owner: Corey Farrell <git@cfware.com> </div>
<div style="display:none"> Gerrit-Reviewer: George Joseph <gjoseph@digium.com> </div>
<div style="display:none"> Gerrit-Reviewer: Jenkins2 </div>
<div style="display:none"> Gerrit-Reviewer: Joshua Colp <jcolp@digium.com> </div>