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

</div><pre style="font-family: monospace,monospace; white-space: pre-wrap;">Geolocation: Base Asterisk Prereqs<br><br>* Added ast_variable_list_from_quoted_string()<br>  Parse a quoted string into an ast_variable list.<br><br>* Added ast_str_substitute_variables_full2()<br>  Perform variable/function/expression substitution on an ast_str.<br><br>* Added ast_strsep_quoted()<br>  Like ast_strsep except you can specify a specific quote character.<br>  Also added unit test.<br><br>* Added ast_xml_find_child_element()<br>  Find a direct child element by name.<br><br>* Added ast_xml_doc_dump_memory()<br>  Dump the specified document to a buffer<br><br>* ast_datastore_free() now checks for a NULL datastore<br>  before attempting to destroy it.<br><br>Change-Id: I5dcefed2f5f93a109e8b489e18d80d42e45244ec<br>---<br>M include/asterisk/config.h<br>M include/asterisk/pbx.h<br>M include/asterisk/strings.h<br>M include/asterisk/xml.h<br>M main/config.c<br>M main/datastore.c<br>M main/pbx_variables.c<br>M main/utils.c<br>M main/xml.c<br>M tests/test_config.c<br>M tests/test_strings.c<br>11 files changed, 358 insertions(+), 20 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/include/asterisk/config.h b/include/asterisk/config.h</span><br><span>index 50b358e..7fecbed 100644</span><br><span>--- a/include/asterisk/config.h</span><br><span>+++ b/include/asterisk/config.h</span><br><span>@@ -1022,6 +1022,26 @@</span><br><span>      const char *name_value_separator);</span><br><span> </span><br><span> /*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Parse a string into an ast_variable list.  The reverse of ast_variable_list_join</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param input                The name-value pair string to parse.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param item_separator       The string used to separate the list items.</span><br><span style="color: hsl(120, 100%, 40%);">+ *                             Only the first character in the string will be used.</span><br><span style="color: hsl(120, 100%, 40%);">+ *                             If NULL, "," will be used.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param name_value_separator The string used to separate each item's name and value.</span><br><span style="color: hsl(120, 100%, 40%);">+ *                             Only the first character in the string will be used.</span><br><span style="color: hsl(120, 100%, 40%);">+ *                             If NULL, "=" will be used.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param quote_str            The string used to quote values.</span><br><span style="color: hsl(120, 100%, 40%);">+ *                             Only the first character in the string will be used.</span><br><span style="color: hsl(120, 100%, 40%);">+ *                             If NULL, '"' will be used.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval A pointer to a list of ast_variables.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval NULL if there was an error or no variables could be parsed.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+struct ast_variable *ast_variable_list_from_quoted_string(const char *input, const char *item_separator,</span><br><span style="color: hsl(120, 100%, 40%);">+     const char *name_value_separator, const char *quote_str);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span>  * \brief Update variable value within a config</span><br><span>  *</span><br><span>  * \param category Category element within the config</span><br><span>diff --git a/include/asterisk/pbx.h b/include/asterisk/pbx.h</span><br><span>index f2247d2..a1bf662 100644</span><br><span>--- a/include/asterisk/pbx.h</span><br><span>+++ b/include/asterisk/pbx.h</span><br><span>@@ -1439,6 +1439,28 @@</span><br><span>  * \param used Number of bytes read from the template.  (May be NULL)</span><br><span>  */</span><br><span> void ast_str_substitute_variables_full(struct ast_str **buf, ssize_t maxlen, struct ast_channel *c, struct varshead *headp, const char *templ, size_t *used);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Perform variable/function/expression substitution on an ast_str</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param buf      Result will be placed in this buffer.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param maxlen   -1 if the buffer should not grow, 0 if the buffer</span><br><span style="color: hsl(120, 100%, 40%);">+ *                 may grow to any size, and >0 if the buffer should</span><br><span style="color: hsl(120, 100%, 40%);">+ *                 grow only to that number of bytes.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param c        A channel from which to extract values, and to pass</span><br><span style="color: hsl(120, 100%, 40%);">+ *                 to any dialplan functions.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param headp    A channel variables list to also search for variables.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param templ    Variable template to expand.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param used     Number of bytes read from the template.  (May be NULL)</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param use_both Normally, if a channel is specified, headp is ignored.</span><br><span style="color: hsl(120, 100%, 40%);">+ *                 If this parameter is set to 1 and both a channel and headp</span><br><span style="color: hsl(120, 100%, 40%);">+ *                 are specified, the channel will be searched for variables</span><br><span style="color: hsl(120, 100%, 40%);">+ *                 first and any not found will be searched for in headp.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+void ast_str_substitute_variables_full2(struct ast_str **buf, ssize_t maxlen,</span><br><span style="color: hsl(120, 100%, 40%);">+  struct ast_channel *c, struct varshead *headp, const char *templ,</span><br><span style="color: hsl(120, 100%, 40%);">+     size_t *used, int use_both);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /*! @} */</span><br><span> </span><br><span> int ast_extension_patmatch(const char *pattern, const char *data);</span><br><span>diff --git a/include/asterisk/strings.h b/include/asterisk/strings.h</span><br><span>index 325491a..58cb7f3 100644</span><br><span>--- a/include/asterisk/strings.h</span><br><span>+++ b/include/asterisk/strings.h</span><br><span>@@ -305,6 +305,24 @@</span><br><span> char *ast_strsep(char **s, const char sep, uint32_t flags);</span><br><span> </span><br><span> /*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Like ast_strsep() except you can specify a specific quote character</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+  \param s Pointer to address of the string to be processed.</span><br><span style="color: hsl(120, 100%, 40%);">+  Will be modified and can't be constant.</span><br><span style="color: hsl(120, 100%, 40%);">+  \param sep A single character delimiter.</span><br><span style="color: hsl(120, 100%, 40%);">+  \param quote The quote character</span><br><span style="color: hsl(120, 100%, 40%);">+  \param flags Controls post-processing of the result.</span><br><span style="color: hsl(120, 100%, 40%);">+  AST_STRSEP_TRIM trims all leading and trailing whitespace from the result.</span><br><span style="color: hsl(120, 100%, 40%);">+  AST_STRSEP_STRIP does a trim then strips the outermost quotes.  You may want</span><br><span style="color: hsl(120, 100%, 40%);">+  to trim again after the strip.  Just OR both the TRIM and STRIP flags.</span><br><span style="color: hsl(120, 100%, 40%);">+  AST_STRSEP_UNESCAPE unescapes '\' sequences.</span><br><span style="color: hsl(120, 100%, 40%);">+  AST_STRSEP_ALL does all of the above processing.</span><br><span style="color: hsl(120, 100%, 40%);">+  \return The next token or NULL if done or if there are more than 8 levels of</span><br><span style="color: hsl(120, 100%, 40%);">+  nested quotes.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+char *ast_strsep_quoted(char **s, const char sep, const char quote, uint32_t flags);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span>   \brief Strip backslash for "escaped" semicolons,</span><br><span>  the string to be stripped (will be modified).</span><br><span>   \return The stripped string.</span><br><span>diff --git a/include/asterisk/xml.h b/include/asterisk/xml.h</span><br><span>index 7b30ed8..439b0aa 100644</span><br><span>--- a/include/asterisk/xml.h</span><br><span>+++ b/include/asterisk/xml.h</span><br><span>@@ -189,6 +189,18 @@</span><br><span> struct ast_xml_ns *ast_xml_find_namespace(struct ast_xml_doc *doc, struct ast_xml_node *node, const char *ns_name);</span><br><span> </span><br><span> /*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Find a direct child element by name.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param parent_node This is the parent node to search.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param name Node name to find.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param attrname attribute name to match (if NULL it won't be matched).</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param attrvalue attribute value to match (if NULL it won't be matched).</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval NULL if not found.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \return The node on success.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+#define ast_xml_find_child_element(_parent_node, _name, _attrname, _attrvalue) \</span><br><span style="color: hsl(120, 100%, 40%);">+    ast_xml_find_element(ast_xml_node_get_children(_parent_node), _name, _attrname, _attrvalue)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span>  * \brief Get the prefix of a namespace.</span><br><span>  * \param ns The namespace</span><br><span>  * \return The prefix of the namespace.</span><br><span>@@ -249,6 +261,17 @@</span><br><span> int ast_xml_doc_dump_file(FILE *output, struct ast_xml_doc *doc);</span><br><span> </span><br><span> /*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Dump the specified document to a buffer</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param doc The XML doc to dump</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param buffer A pointer to a char * to receive the address of the results</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param length A pointer to an int to receive the length of the results</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \note The result buffer must be freed with ast_xml_free_text().</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+void ast_xml_doc_dump_memory(struct ast_xml_doc *doc, char **buffer, int *length);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span>  * \brief Free the XPath results</span><br><span>  * \param results The XPath results object to dispose of</span><br><span>  *</span><br><span>diff --git a/main/config.c b/main/config.c</span><br><span>index da893b6..8bae47e 100644</span><br><span>--- a/main/config.c</span><br><span>+++ b/main/config.c</span><br><span>@@ -724,11 +724,12 @@</span><br><span>      return local_str;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-struct ast_variable *ast_variable_list_from_string(const char *input, const char *item_separator,</span><br><span style="color: hsl(0, 100%, 40%);">-     const char *name_value_separator)</span><br><span style="color: hsl(120, 100%, 40%);">+struct ast_variable *ast_variable_list_from_quoted_string(const char *input, const char *item_separator,</span><br><span style="color: hsl(120, 100%, 40%);">+   const char *name_value_separator, const char *quote_str)</span><br><span> {</span><br><span>        char item_sep;</span><br><span>       char nv_sep;</span><br><span style="color: hsl(120, 100%, 40%);">+  char quote;</span><br><span>  struct ast_variable *new_list = NULL;</span><br><span>        struct ast_variable *new_var = NULL;</span><br><span>         char *item_string;</span><br><span>@@ -742,11 +743,22 @@</span><br><span> </span><br><span>       item_sep = ast_strlen_zero(item_separator) ? ',' : item_separator[0];</span><br><span>        nv_sep = ast_strlen_zero(name_value_separator) ? '=' : name_value_separator[0];</span><br><span style="color: hsl(120, 100%, 40%);">+       quote = ast_strlen_zero(quote_str) ? '"' : quote_str[0];</span><br><span>        item_string = ast_strip(ast_strdupa(input));</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-        while ((item = ast_strsep(&item_string, item_sep, AST_STRSEP_ALL))) {</span><br><span style="color: hsl(0, 100%, 40%);">-               item_name = ast_strsep(&item, nv_sep, AST_STRSEP_ALL);</span><br><span style="color: hsl(0, 100%, 40%);">-              item_value = ast_strsep(&item, nv_sep, AST_STRSEP_ALL);</span><br><span style="color: hsl(120, 100%, 40%);">+   while ((item = ast_strsep_quoted(&item_string, item_sep, quote, AST_STRSEP_ALL))) {</span><br><span style="color: hsl(120, 100%, 40%);">+               item_name = ast_strsep_quoted(&item, nv_sep, quote, AST_STRSEP_ALL);</span><br><span style="color: hsl(120, 100%, 40%);">+              if (!item_name) {</span><br><span style="color: hsl(120, 100%, 40%);">+                     ast_variables_destroy(new_list);</span><br><span style="color: hsl(120, 100%, 40%);">+                      return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+          }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           item_value = ast_strsep_quoted(&item, nv_sep, quote, AST_STRSEP_ALL);</span><br><span style="color: hsl(120, 100%, 40%);">+             if (!item_value) {</span><br><span style="color: hsl(120, 100%, 40%);">+                    ast_variables_destroy(new_list);</span><br><span style="color: hsl(120, 100%, 40%);">+                      return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+          }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>          new_var = ast_variable_new(item_name, item_value, "");</span><br><span>             if (!new_var) {</span><br><span>                      ast_variables_destroy(new_list);</span><br><span>@@ -757,6 +769,12 @@</span><br><span>      return new_list;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+struct ast_variable *ast_variable_list_from_string(const char *input, const char *item_separator,</span><br><span style="color: hsl(120, 100%, 40%);">+  const char *name_value_separator)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  return ast_variable_list_from_quoted_string(input, item_separator, name_value_separator, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> const char *ast_config_option(struct ast_config *cfg, const char *cat, const char *var)</span><br><span> {</span><br><span>         const char *tmp;</span><br><span>diff --git a/main/datastore.c b/main/datastore.c</span><br><span>index f37ee6c..d5adfae 100644</span><br><span>--- a/main/datastore.c</span><br><span>+++ b/main/datastore.c</span><br><span>@@ -69,6 +69,10 @@</span><br><span> {</span><br><span>      int res = 0;</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+      if (!datastore) {</span><br><span style="color: hsl(120, 100%, 40%);">+             return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>  /* Using the destroy function (if present) destroy the data */</span><br><span>       if (datastore->info->destroy != NULL && datastore->data != NULL) {</span><br><span>          datastore->info->destroy(datastore->data);</span><br><span>diff --git a/main/pbx_variables.c b/main/pbx_variables.c</span><br><span>index 91b5bbb..cc5f015 100644</span><br><span>--- a/main/pbx_variables.c</span><br><span>+++ b/main/pbx_variables.c</span><br><span>@@ -391,7 +391,9 @@</span><br><span>       return ret;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-void ast_str_substitute_variables_full(struct ast_str **buf, ssize_t maxlen, struct ast_channel *c, struct varshead *headp, const char *templ, size_t *used)</span><br><span style="color: hsl(120, 100%, 40%);">+void ast_str_substitute_variables_full2(struct ast_str **buf, ssize_t maxlen,</span><br><span style="color: hsl(120, 100%, 40%);">+       struct ast_channel *c, struct varshead *headp, const char *templ,</span><br><span style="color: hsl(120, 100%, 40%);">+     size_t *used, int use_both)</span><br><span> {</span><br><span>     /* Substitutes variables into buf, based on string templ */</span><br><span>  const char *whereweare;</span><br><span>@@ -498,7 +500,8 @@</span><br><span> </span><br><span>                    /* Store variable name expression to lookup. */</span><br><span>                      ast_str_set_substr(&substr1, 0, vars, len);</span><br><span style="color: hsl(0, 100%, 40%);">-                 ast_debug(5, "Evaluating '%s' (from '%s' len %d)\n", ast_str_buffer(substr1), vars, len);</span><br><span style="color: hsl(120, 100%, 40%);">+                   ast_debug(5, "Evaluating '%s' (from '%s' len %d)\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                                ast_str_buffer(substr1), vars, len);</span><br><span> </span><br><span>                     /* Substitute if necessary */</span><br><span>                        if (needsub) {</span><br><span>@@ -508,7 +511,8 @@</span><br><span>                                                 continue;</span><br><span>                                    }</span><br><span>                            }</span><br><span style="color: hsl(0, 100%, 40%);">-                               ast_str_substitute_variables_full(&substr2, 0, c, headp, ast_str_buffer(substr1), NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+                          ast_str_substitute_variables_full2(&substr2, 0, c, headp,</span><br><span style="color: hsl(120, 100%, 40%);">+                                 ast_str_buffer(substr1), NULL, use_both);</span><br><span>                            finalvars = ast_str_buffer(substr2);</span><br><span>                         } else {</span><br><span>                             finalvars = ast_str_buffer(substr1);</span><br><span>@@ -517,31 +521,48 @@</span><br><span>                         parse_variable_name(finalvars, &offset, &offset2, &isfunction);</span><br><span>                  if (isfunction) {</span><br><span>                            /* Evaluate function */</span><br><span style="color: hsl(0, 100%, 40%);">-                         if (c || !headp) {</span><br><span style="color: hsl(120, 100%, 40%);">+                            res = -1;</span><br><span style="color: hsl(120, 100%, 40%);">+                             if (c) {</span><br><span>                                     res = ast_func_read2(c, finalvars, &substr3, 0);</span><br><span style="color: hsl(0, 100%, 40%);">-                            } else {</span><br><span style="color: hsl(120, 100%, 40%);">+                                      ast_debug(2, "Function %s result is '%s' from channel\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                                           finalvars, res ? "" : ast_str_buffer(substr3));</span><br><span style="color: hsl(120, 100%, 40%);">+                             }</span><br><span style="color: hsl(120, 100%, 40%);">+                             if (!c || (c && res < 0 && use_both)) {</span><br><span>                                   struct varshead old;</span><br><span>                                         struct ast_channel *bogus;</span><br><span> </span><br><span>                                       bogus = ast_dummy_channel_alloc();</span><br><span>                                   if (bogus) {</span><br><span>                                                 old = *ast_channel_varshead(bogus);</span><br><span style="color: hsl(0, 100%, 40%);">-                                             *ast_channel_varshead(bogus) = *headp;</span><br><span style="color: hsl(120, 100%, 40%);">+                                                if (headp) {</span><br><span style="color: hsl(120, 100%, 40%);">+                                                  *ast_channel_varshead(bogus) = *headp;</span><br><span style="color: hsl(120, 100%, 40%);">+                                                }</span><br><span>                                            res = ast_func_read2(bogus, finalvars, &substr3, 0);</span><br><span>                                             /* Don't deallocate the varshead that was passed in */</span><br><span style="color: hsl(0, 100%, 40%);">-                                              *ast_channel_varshead(bogus) = old;</span><br><span style="color: hsl(120, 100%, 40%);">+                                           if (headp) {</span><br><span style="color: hsl(120, 100%, 40%);">+                                                  *ast_channel_varshead(bogus) = old;</span><br><span style="color: hsl(120, 100%, 40%);">+                                           }</span><br><span>                                            ast_channel_unref(bogus);</span><br><span>                                    } else {</span><br><span>                                             ast_log(LOG_ERROR, "Unable to allocate bogus channel for function value substitution.\n");</span><br><span>                                                 res = -1;</span><br><span>                                    }</span><br><span style="color: hsl(120, 100%, 40%);">+                                     ast_debug(2, "Function %s result is '%s' from headp\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                                             finalvars, res ? "" : ast_str_buffer(substr3));</span><br><span>                            }</span><br><span style="color: hsl(0, 100%, 40%);">-                               ast_debug(2, "Function %s result is '%s'\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                                  finalvars, res ? "" : ast_str_buffer(substr3));</span><br><span>                    } else {</span><br><span style="color: hsl(0, 100%, 40%);">-                                /* Retrieve variable value */</span><br><span style="color: hsl(0, 100%, 40%);">-                           ast_str_retrieve_variable(&substr3, 0, c, headp, finalvars);</span><br><span style="color: hsl(0, 100%, 40%);">-                                res = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+                              const char *result;</span><br><span style="color: hsl(120, 100%, 40%);">+                           if (c) {</span><br><span style="color: hsl(120, 100%, 40%);">+                                      result = ast_str_retrieve_variable(&substr3, 0, c, NULL, finalvars);</span><br><span style="color: hsl(120, 100%, 40%);">+                                      ast_debug(2, "Variable %s result is '%s' from channel\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                                           finalvars, S_OR(result, ""));</span><br><span style="color: hsl(120, 100%, 40%);">+                               }</span><br><span style="color: hsl(120, 100%, 40%);">+                             if (!c || (c && !result && use_both)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                                       result = ast_str_retrieve_variable(&substr3, 0, NULL, headp, finalvars);</span><br><span style="color: hsl(120, 100%, 40%);">+                                  ast_debug(2, "Variable %s result is '%s' from headp\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                                             finalvars, S_OR(result, ""));</span><br><span style="color: hsl(120, 100%, 40%);">+                               }</span><br><span style="color: hsl(120, 100%, 40%);">+                             res = (result ? 0 : -1);</span><br><span>                     }</span><br><span>                    if (!res) {</span><br><span>                          ast_str_substring(substr3, offset, offset2);</span><br><span>@@ -593,7 +614,8 @@</span><br><span>                                           continue;</span><br><span>                                    }</span><br><span>                            }</span><br><span style="color: hsl(0, 100%, 40%);">-                               ast_str_substitute_variables_full(&substr2, 0, c, headp, ast_str_buffer(substr1), NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+                          ast_str_substitute_variables_full2(&substr2, 0, c, headp,</span><br><span style="color: hsl(120, 100%, 40%);">+                                 ast_str_buffer(substr1), NULL, use_both);</span><br><span>                            finalvars = ast_str_buffer(substr2);</span><br><span>                         } else {</span><br><span>                             finalvars = ast_str_buffer(substr1);</span><br><span>@@ -613,6 +635,12 @@</span><br><span>  ast_free(substr3);</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+void ast_str_substitute_variables_full(struct ast_str **buf, ssize_t maxlen,</span><br><span style="color: hsl(120, 100%, 40%);">+     struct ast_channel *chan, struct varshead *headp, const char *templ, size_t *used)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_str_substitute_variables_full2(buf, maxlen, chan, headp, templ, used, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> void ast_str_substitute_variables(struct ast_str **buf, ssize_t maxlen, struct ast_channel *chan, const char *templ)</span><br><span> {</span><br><span>      ast_str_substitute_variables_full(buf, maxlen, chan, NULL, templ, NULL);</span><br><span>diff --git a/main/utils.c b/main/utils.c</span><br><span>index dc94c99..bb16309 100644</span><br><span>--- a/main/utils.c</span><br><span>+++ b/main/utils.c</span><br><span>@@ -1857,6 +1857,67 @@</span><br><span>       return st;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+char *ast_strsep_quoted(char **iss, const char sep, const char quote, uint32_t flags)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ char *st = *iss;</span><br><span style="color: hsl(120, 100%, 40%);">+      char *is;</span><br><span style="color: hsl(120, 100%, 40%);">+     int inquote = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+      int found = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+        char stack[8];</span><br><span style="color: hsl(120, 100%, 40%);">+        const char qstr[] = { quote };</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      if (ast_strlen_zero(st)) {</span><br><span style="color: hsl(120, 100%, 40%);">+            return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   memset(stack, 0, sizeof(stack));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    for(is = st; *is; is++) {</span><br><span style="color: hsl(120, 100%, 40%);">+             if (*is == '\\') {</span><br><span style="color: hsl(120, 100%, 40%);">+                    if (*++is != '\0') {</span><br><span style="color: hsl(120, 100%, 40%);">+                          is++;</span><br><span style="color: hsl(120, 100%, 40%);">+                 } else {</span><br><span style="color: hsl(120, 100%, 40%);">+                              break;</span><br><span style="color: hsl(120, 100%, 40%);">+                        }</span><br><span style="color: hsl(120, 100%, 40%);">+             }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           if (*is == quote) {</span><br><span style="color: hsl(120, 100%, 40%);">+                   if (*is == stack[inquote]) {</span><br><span style="color: hsl(120, 100%, 40%);">+                          stack[inquote--] = '\0';</span><br><span style="color: hsl(120, 100%, 40%);">+                      } else {</span><br><span style="color: hsl(120, 100%, 40%);">+                              if (++inquote >= sizeof(stack)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                                  return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+                          }</span><br><span style="color: hsl(120, 100%, 40%);">+                             stack[inquote] = *is;</span><br><span style="color: hsl(120, 100%, 40%);">+                 }</span><br><span style="color: hsl(120, 100%, 40%);">+             }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           if (*is == sep && !inquote) {</span><br><span style="color: hsl(120, 100%, 40%);">+                 *is = '\0';</span><br><span style="color: hsl(120, 100%, 40%);">+                   found = 1;</span><br><span style="color: hsl(120, 100%, 40%);">+                    *iss = is + 1;</span><br><span style="color: hsl(120, 100%, 40%);">+                        break;</span><br><span style="color: hsl(120, 100%, 40%);">+                }</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!found) {</span><br><span style="color: hsl(120, 100%, 40%);">+         *iss = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (flags & AST_STRSEP_STRIP) {</span><br><span style="color: hsl(120, 100%, 40%);">+           st = ast_strip_quoted(st, qstr, qstr);</span><br><span style="color: hsl(120, 100%, 40%);">+        }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (flags & AST_STRSEP_TRIM) {</span><br><span style="color: hsl(120, 100%, 40%);">+            st = ast_strip(st);</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (flags & AST_STRSEP_UNESCAPE) {</span><br><span style="color: hsl(120, 100%, 40%);">+                ast_unescape_quoted(st);</span><br><span style="color: hsl(120, 100%, 40%);">+      }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return st;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> char *ast_unescape_semicolon(char *s)</span><br><span> {</span><br><span>        char *e;</span><br><span>diff --git a/main/xml.c b/main/xml.c</span><br><span>index 987f125..d244e4e 100644</span><br><span>--- a/main/xml.c</span><br><span>+++ b/main/xml.c</span><br><span>@@ -361,6 +361,11 @@</span><br><span>         return xmlDocDump(output, (xmlDocPtr)doc);</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+void ast_xml_doc_dump_memory(struct ast_xml_doc *doc, char **buffer, int *length)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     xmlDocDumpFormatMemory((xmlDocPtr)doc, (xmlChar **)buffer, length, 1);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> const char *ast_xml_node_get_name(struct ast_xml_node *node)</span><br><span> {</span><br><span>     return (const char *) ((xmlNode *) node)->name;</span><br><span>diff --git a/tests/test_config.c b/tests/test_config.c</span><br><span>index 1a0ddaf..166879a 100644</span><br><span>--- a/tests/test_config.c</span><br><span>+++ b/tests/test_config.c</span><br><span>@@ -1952,7 +1952,7 @@</span><br><span> </span><br><span>      switch (cmd) {</span><br><span>       case TEST_INIT:</span><br><span style="color: hsl(0, 100%, 40%);">-         info->name = "variable_list_from_string";</span><br><span style="color: hsl(120, 100%, 40%);">+                info->name = "variable_list_from_quoted_string";</span><br><span>                info->category = "/main/config/";</span><br><span>               info->summary = "Test parsing a string into a variable list";</span><br><span>           info->description =  info->summary;</span><br><span>@@ -1962,7 +1962,7 @@</span><br><span>    }</span><br><span> </span><br><span>        parse_string = "abc = 'def', ghi = 'j,kl', mno='pq=r', stu = 'vwx=\"yz\", ABC = \"DEF\"'";</span><br><span style="color: hsl(0, 100%, 40%);">-        list = ast_variable_list_from_string(parse_string, ",", "=");</span><br><span style="color: hsl(120, 100%, 40%);">+     list = ast_variable_list_from_quoted_string(parse_string, ",", "=", "'");</span><br><span>  ast_test_validate(test, list != NULL);</span><br><span>       str = ast_variable_list_join(list, "|", "^", "@", NULL);</span><br><span> </span><br><span>diff --git a/tests/test_strings.c b/tests/test_strings.c</span><br><span>index f3c7e56..a121056 100644</span><br><span>--- a/tests/test_strings.c</span><br><span>+++ b/tests/test_strings.c</span><br><span>@@ -385,6 +385,143 @@</span><br><span>      return AST_TEST_PASS;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+AST_TEST_DEFINE(strsep_quoted_test)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        char *test1, *test2, *test3;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        switch (cmd) {</span><br><span style="color: hsl(120, 100%, 40%);">+        case TEST_INIT:</span><br><span style="color: hsl(120, 100%, 40%);">+               info->name = "strsep_quoted";</span><br><span style="color: hsl(120, 100%, 40%);">+            info->category = "/main/strings/";</span><br><span style="color: hsl(120, 100%, 40%);">+               info->summary = "Test ast_strsep_quoted";</span><br><span style="color: hsl(120, 100%, 40%);">+                info->description = "Test ast_strsep_quoted";</span><br><span style="color: hsl(120, 100%, 40%);">+            return AST_TEST_NOT_RUN;</span><br><span style="color: hsl(120, 100%, 40%);">+      case TEST_EXECUTE:</span><br><span style="color: hsl(120, 100%, 40%);">+            break;</span><br><span style="color: hsl(120, 100%, 40%);">+        }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   test1 = ast_strdupa("ghi=jkl,mno=\"pqr,stu\",abc=def, vwx = yz1 ,  vwx = yz1 ,  "</span><br><span style="color: hsl(120, 100%, 40%);">+         "\" vwx = yz1 \" ,  \" vwx , yz1 \",v'w'x, \"'x,v','x'\" , \" i\\'m a test\""</span><br><span style="color: hsl(120, 100%, 40%);">+           ", \" i\\'m a, test\", \" i\\'m a, test\", e\\,nd, end\\");</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   test2 = ast_strsep_quoted(&test1, ',', '"', 0);</span><br><span style="color: hsl(120, 100%, 40%);">+      ast_test_validate(test, 0 == strcmp("ghi=jkl", test2));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   test3 = ast_strsep_quoted(&test2, '=', '"', 0);</span><br><span style="color: hsl(120, 100%, 40%);">+      ast_test_validate(test, 0 == strcmp("ghi", test3));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       test3 = ast_strsep_quoted(&test2, '=', '"', 0);</span><br><span style="color: hsl(120, 100%, 40%);">+      ast_test_validate(test, 0 == strcmp("jkl", test3));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       test2 = ast_strsep_quoted(&test1, ',', '"', 0);</span><br><span style="color: hsl(120, 100%, 40%);">+      ast_test_validate(test, 0 == strcmp("mno=\"pqr,stu\"", test2));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ test3 = ast_strsep_quoted(&test2, '=', '"', 0);</span><br><span style="color: hsl(120, 100%, 40%);">+      ast_test_validate(test, 0 == strcmp("mno", test3));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       test3 = ast_strsep_quoted(&test2, '=', '"', 0);</span><br><span style="color: hsl(120, 100%, 40%);">+      ast_test_validate(test, 0 == strcmp("\"pqr,stu\"", test3));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     test2 = ast_strsep_quoted(&test1, ',', '"', 0);</span><br><span style="color: hsl(120, 100%, 40%);">+      ast_test_validate(test, 0 == strcmp("abc=def", test2));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   test2 = ast_strsep_quoted(&test1, ',', '"', 0);</span><br><span style="color: hsl(120, 100%, 40%);">+      ast_test_validate(test, 0 == strcmp(" vwx = yz1 ", test2));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       test2 = ast_strsep_quoted(&test1, ',', '"', AST_STRSEP_TRIM);</span><br><span style="color: hsl(120, 100%, 40%);">+        ast_test_validate(test, 0 == strcmp("vwx = yz1", test2));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ test2 = ast_strsep_quoted(&test1, ',', '"', AST_STRSEP_STRIP);</span><br><span style="color: hsl(120, 100%, 40%);">+       ast_test_validate(test, 0 == strcmp(" vwx = yz1 ", test2));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       test2 = ast_strsep_quoted(&test1, ',', '"', AST_STRSEP_STRIP | AST_STRSEP_TRIM);</span><br><span style="color: hsl(120, 100%, 40%);">+     ast_test_validate(test, 0 == strcmp("vwx , yz1", test2));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ test2 = ast_strsep_quoted(&test1, ',', '"', AST_STRSEP_STRIP | AST_STRSEP_TRIM);</span><br><span style="color: hsl(120, 100%, 40%);">+     ast_test_validate(test, 0 == strcmp("v'w'x", test2));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     test2 = ast_strsep_quoted(&test1, ',', '"', AST_STRSEP_TRIM);</span><br><span style="color: hsl(120, 100%, 40%);">+        ast_test_validate(test, 0 == strcmp("\"'x,v','x'\"", test2));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   test2 = ast_strsep_quoted(&test1, ',', '"', AST_STRSEP_TRIM);</span><br><span style="color: hsl(120, 100%, 40%);">+        ast_test_validate(test, 0 == strcmp("\" i\\'m a test\"", test2));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   test2 = ast_strsep_quoted(&test1, ',', '"', AST_STRSEP_TRIM | AST_STRSEP_UNESCAPE);</span><br><span style="color: hsl(120, 100%, 40%);">+  ast_test_validate(test, 0 == strcmp("\" i'm a, test\"", test2));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    test2 = ast_strsep_quoted(&test1, ',', '"', AST_STRSEP_ALL);</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_test_validate(test, 0 == strcmp("i'm a, test", test2));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   test2 = ast_strsep_quoted(&test1, ',', '"', AST_STRSEP_TRIM | AST_STRSEP_UNESCAPE);</span><br><span style="color: hsl(120, 100%, 40%);">+  ast_test_validate(test, 0 == strcmp("e,nd", test2));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      test2 = ast_strsep_quoted(&test1, ',', '"', AST_STRSEP_TRIM | AST_STRSEP_UNESCAPE);</span><br><span style="color: hsl(120, 100%, 40%);">+  ast_test_validate(test, 0 == strcmp("end", test2));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       // Now use '|' as the quote character</span><br><span style="color: hsl(120, 100%, 40%);">+ test1 = ast_strdupa("ghi=jkl,mno=|pqr,stu|,abc=def, vwx = yz1 ,  vwx = yz1 ,  "</span><br><span style="color: hsl(120, 100%, 40%);">+             "| vwx = yz1 | ,  | vwx , yz1 |,v'w'x, |'x,v','x'| , | i\\'m a test|"</span><br><span style="color: hsl(120, 100%, 40%);">+           ", | i\\'m a, test|, | i\\'m a, test|, e\\,nd, end\\");</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   test2 = ast_strsep_quoted(&test1, ',', '|', 0);</span><br><span style="color: hsl(120, 100%, 40%);">+   ast_test_validate(test, 0 == strcmp("ghi=jkl", test2));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   test3 = ast_strsep_quoted(&test2, '=', '|', 0);</span><br><span style="color: hsl(120, 100%, 40%);">+   ast_test_validate(test, 0 == strcmp("ghi", test3));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       test3 = ast_strsep_quoted(&test2, '=', '|', 0);</span><br><span style="color: hsl(120, 100%, 40%);">+   ast_test_validate(test, 0 == strcmp("jkl", test3));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       test2 = ast_strsep_quoted(&test1, ',', '|', 0);</span><br><span style="color: hsl(120, 100%, 40%);">+   ast_test_validate(test, 0 == strcmp("mno=|pqr,stu|", test2));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     test3 = ast_strsep_quoted(&test2, '=', '|', 0);</span><br><span style="color: hsl(120, 100%, 40%);">+   ast_test_validate(test, 0 == strcmp("mno", test3));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       test3 = ast_strsep_quoted(&test2, '=', '|', 0);</span><br><span style="color: hsl(120, 100%, 40%);">+   ast_test_validate(test, 0 == strcmp("|pqr,stu|", test3));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ test2 = ast_strsep_quoted(&test1, ',', '|', 0);</span><br><span style="color: hsl(120, 100%, 40%);">+   ast_test_validate(test, 0 == strcmp("abc=def", test2));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   test2 = ast_strsep_quoted(&test1, ',', '|', 0);</span><br><span style="color: hsl(120, 100%, 40%);">+   ast_test_validate(test, 0 == strcmp(" vwx = yz1 ", test2));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       test2 = ast_strsep_quoted(&test1, ',', '|', AST_STRSEP_TRIM);</span><br><span style="color: hsl(120, 100%, 40%);">+     ast_test_validate(test, 0 == strcmp("vwx = yz1", test2));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ test2 = ast_strsep_quoted(&test1, ',', '|', AST_STRSEP_STRIP);</span><br><span style="color: hsl(120, 100%, 40%);">+    ast_test_validate(test, 0 == strcmp(" vwx = yz1 ", test2));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       test2 = ast_strsep_quoted(&test1, ',', '|', AST_STRSEP_STRIP | AST_STRSEP_TRIM);</span><br><span style="color: hsl(120, 100%, 40%);">+  ast_test_validate(test, 0 == strcmp("vwx , yz1", test2));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ test2 = ast_strsep_quoted(&test1, ',', '|', AST_STRSEP_STRIP | AST_STRSEP_TRIM);</span><br><span style="color: hsl(120, 100%, 40%);">+  ast_test_validate(test, 0 == strcmp("v'w'x", test2));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     test2 = ast_strsep_quoted(&test1, ',', '|', AST_STRSEP_TRIM);</span><br><span style="color: hsl(120, 100%, 40%);">+     ast_test_validate(test, 0 == strcmp("|'x,v','x'|", test2));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       test2 = ast_strsep_quoted(&test1, ',', '|', AST_STRSEP_TRIM);</span><br><span style="color: hsl(120, 100%, 40%);">+     ast_test_validate(test, 0 == strcmp("| i\\'m a test|", test2));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       test2 = ast_strsep_quoted(&test1, ',', '|', AST_STRSEP_TRIM | AST_STRSEP_UNESCAPE);</span><br><span style="color: hsl(120, 100%, 40%);">+       ast_test_validate(test, 0 == strcmp("| i'm a, test|", test2));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        test2 = ast_strsep_quoted(&test1, ',', '|', AST_STRSEP_ALL);</span><br><span style="color: hsl(120, 100%, 40%);">+      ast_test_validate(test, 0 == strcmp("i'm a, test", test2));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   test2 = ast_strsep_quoted(&test1, ',', '|', AST_STRSEP_TRIM | AST_STRSEP_UNESCAPE);</span><br><span style="color: hsl(120, 100%, 40%);">+       ast_test_validate(test, 0 == strcmp("e,nd", test2));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      test2 = ast_strsep_quoted(&test1, ',', '|', AST_STRSEP_TRIM | AST_STRSEP_UNESCAPE);</span><br><span style="color: hsl(120, 100%, 40%);">+       ast_test_validate(test, 0 == strcmp("end", test2));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     // nothing failed; we're all good!</span><br><span style="color: hsl(120, 100%, 40%);">+        return AST_TEST_PASS;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> static int test_semi(char *string1, char *string2, int test_len)</span><br><span> {</span><br><span>  char *test2 = NULL;</span><br><span>@@ -740,6 +877,7 @@</span><br><span>    AST_TEST_UNREGISTER(begins_with_test);</span><br><span>       AST_TEST_UNREGISTER(ends_with_test);</span><br><span>         AST_TEST_UNREGISTER(strsep_test);</span><br><span style="color: hsl(120, 100%, 40%);">+     AST_TEST_UNREGISTER(strsep_quoted_test);</span><br><span>     AST_TEST_UNREGISTER(escape_semicolons_test);</span><br><span>         AST_TEST_UNREGISTER(escape_test);</span><br><span>    AST_TEST_UNREGISTER(strings_match);</span><br><span>@@ -754,6 +892,7 @@</span><br><span>    AST_TEST_REGISTER(begins_with_test);</span><br><span>         AST_TEST_REGISTER(ends_with_test);</span><br><span>   AST_TEST_REGISTER(strsep_test);</span><br><span style="color: hsl(120, 100%, 40%);">+       AST_TEST_REGISTER(strsep_quoted_test);</span><br><span>       AST_TEST_REGISTER(escape_semicolons_test);</span><br><span>   AST_TEST_REGISTER(escape_test);</span><br><span>      AST_TEST_REGISTER(strings_match);</span><br><span></span><br></pre><div style="white-space:pre-wrap"></div><p>To view, visit <a href="https://gerrit.asterisk.org/c/asterisk/+/18796">change 18796</a>. To unsubscribe, or for help writing mail filters, 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/c/asterisk/+/18796"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: asterisk </div>
<div style="display:none"> Gerrit-Branch: certified/18.9 </div>
<div style="display:none"> Gerrit-Change-Id: I5dcefed2f5f93a109e8b489e18d80d42e45244ec </div>
<div style="display:none"> Gerrit-Change-Number: 18796 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: George Joseph <gjoseph@digium.com> </div>
<div style="display:none"> Gerrit-Reviewer: Friendly Automation </div>
<div style="display:none"> Gerrit-Reviewer: George Joseph <gjoseph@digium.com> </div>
<div style="display:none"> Gerrit-Reviewer: Kevin Harwell <kharwell@digium.com> </div>
<div style="display:none"> Gerrit-MessageType: merged </div>