Skip to content

Commit

Permalink
strings/json: Add string delimter match, and object create with vars …
Browse files Browse the repository at this point in the history
…methods

Add a function to check if there is an exact match a one string between
delimiters in another string.

Add a function that will create an ast_json object out of a list of
Asterisk variables. An excludes string can also optionally be passed
in.

Also, add a macro to make it easier to get object integers.

Change-Id: I5f34f18e102126aef3997f19a553a266d70d6226
  • Loading branch information
kharwell authored and gtjoseph committed Oct 28, 2021
1 parent 1031a18 commit 67d1f88
Show file tree
Hide file tree
Showing 6 changed files with 250 additions and 0 deletions.
17 changes: 17 additions & 0 deletions include/asterisk/json.h
Original file line number Diff line number Diff line change
Expand Up @@ -538,6 +538,15 @@ int ast_json_array_extend(struct ast_json *array, struct ast_json *tail);
*/
struct ast_json *ast_json_object_create(void);

/*!
* \brief Create a new JSON object using the given variables
* \param variables A list of Asterisk variables
* \param excludes Comma separated string of variable names to exclude (optional)
* \return Newly allocated object.
* \return \c NULL on error.
*/
struct ast_json *ast_json_object_create_vars(const struct ast_variable *variables, const char *excludes);

/*!
* \brief Get size of JSON object.
* \since 12.0.0
Expand Down Expand Up @@ -572,6 +581,14 @@ struct ast_json *ast_json_object_get(struct ast_json *object, const char *key);
*/
#define ast_json_object_string_get(object, key) ast_json_string_get(ast_json_object_get(object, key))

/*!
* \brief Get an integer field from a JSON object.
* \param integer JSON integer.
* \return Value of a JSON integer.
* \return 0 if \a integer is not a JSON integer.
*/
#define ast_json_object_integer_get(object, key) ast_json_integer_get(ast_json_object_get(object, key))

/*!
* \brief Set a field in a JSON object.
* \since 12.0.0
Expand Down
13 changes: 13 additions & 0 deletions include/asterisk/strings.h
Original file line number Diff line number Diff line change
Expand Up @@ -400,6 +400,19 @@ void ast_copy_string(char *dst, const char *src, size_t size),
}
)

/*!
* \brief Check if there is an exact match for 'needle' between delimiters in 'haystack'.
*
* \note This will skip extra leading spaces between delimiters.
*
* \param needle The string to search for
* \param haystack The string searched in
* \param delim The haystack delimiter
*
* \return True if an exact match for needle is in haystack, false otherwise
*/
int ast_in_delimited_string(const char *needle, const char *haystack, char delim);

/*!
\brief Build a string in a buffer, designed to be called repeatedly
Expand Down
19 changes: 19 additions & 0 deletions main/json.c
Original file line number Diff line number Diff line change
Expand Up @@ -852,3 +852,22 @@ struct ast_json *ast_json_channel_vars(struct varshead *channelvars)

return ret;
}

struct ast_json *ast_json_object_create_vars(const struct ast_variable *variables, const char *excludes)
{
const struct ast_variable *i;
struct ast_json *obj;

obj = ast_json_object_create();
if (!obj) {
return NULL;
}

for (i = variables; i; i = i->next) {
if (!excludes || !ast_in_delimited_string(i->name, excludes, ',')) {
ast_json_object_set(obj, i->name, ast_json_string_create(i->value));
}
}

return obj;
}
25 changes: 25 additions & 0 deletions main/strings.c
Original file line number Diff line number Diff line change
Expand Up @@ -430,3 +430,28 @@ int ast_vector_string_split(struct ast_vector_string *dest,

return 0;
}

int ast_in_delimited_string(const char *needle, const char *haystack, char delim)
{
const char *end;
unsigned long needle_size;

ast_assert(haystack != NULL);

if (!needle) {
return 0;
}

needle_size = strlen(needle);
haystack = ast_skip_blanks(haystack);

while ((end = strchr(haystack, delim))) {
if (needle_size == end - haystack && !strncmp(haystack, needle, needle_size)) {
return 1;
}
haystack = ast_skip_blanks(end + 1);
}

return strcmp(haystack, needle) ? 0 : -1;
}

60 changes: 60 additions & 0 deletions tests/test_json.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@

#include "asterisk.h"

#include "asterisk/config.h"
#include "asterisk/json.h"
#include "asterisk/module.h"
#include "asterisk/test.h"
Expand Down Expand Up @@ -1090,6 +1091,63 @@ AST_TEST_DEFINE(json_test_object_iter_null)
return AST_TEST_PASS;
}

AST_TEST_DEFINE(json_test_object_create_vars)
{
RAII_VAR(struct ast_json *, uut, NULL, ast_json_unref);
RAII_VAR(struct ast_variable *, vars, NULL, ast_variables_destroy);
const char *value;
struct ast_variable *new_var;

switch (cmd) {
case TEST_INIT:
info->name = "object_create_vars";
info->category = CATEGORY;
info->summary = "Testing JSON object creation initialized using Asterisk variables.";
info->description = "Test JSON abstraction library.";
return AST_TEST_NOT_RUN;
case TEST_EXECUTE:
break;
}

/* NULL case */
ast_test_validate(test, (uut = ast_json_object_create_vars(NULL, NULL)));
ast_test_validate(test, !(value = ast_json_object_string_get(uut, "foo")));

ast_test_validate(test, (new_var = ast_variable_new("foo", "bar", "")));
ast_variable_list_append(&vars, new_var);
ast_test_validate(test, (new_var = ast_variable_new("bar", "baz", "")));
ast_variable_list_append(&vars, new_var);

/* Variables case */
ast_json_unref(uut);
ast_test_validate(test, (uut = ast_json_object_create_vars(vars, NULL)));
ast_test_validate(test, (value = ast_json_object_string_get(uut, "foo")));
ast_test_validate(test, !strcmp("bar", value));
ast_test_validate(test, (value = ast_json_object_string_get(uut, "bar")));
ast_test_validate(test, !strcmp("baz", value));

/* Variables with excludes case */
ast_json_unref(uut);
ast_test_validate(test, (uut = ast_json_object_create_vars(vars, "foo")));
ast_test_validate(test, !(value = ast_json_object_string_get(uut, "foo")));
ast_test_validate(test, (value = ast_json_object_string_get(uut, "bar")));
ast_test_validate(test, !strcmp("baz", value));

ast_json_unref(uut);
ast_test_validate(test, (uut = ast_json_object_create_vars(vars, "foo2")));
ast_test_validate(test, (value = ast_json_object_string_get(uut, "foo")));
ast_test_validate(test, (value = ast_json_object_string_get(uut, "bar")));
ast_test_validate(test, !strcmp("baz", value));

ast_json_unref(uut);
ast_test_validate(test, (uut = ast_json_object_create_vars(vars, "foobar,baz")));
ast_test_validate(test, (value = ast_json_object_string_get(uut, "foo")));
ast_test_validate(test, (value = ast_json_object_string_get(uut, "bar")));
ast_test_validate(test, !strcmp("baz", value));

return AST_TEST_PASS;
}

AST_TEST_DEFINE(json_test_dump_load_string)
{
RAII_VAR(struct ast_json *, uut, NULL, ast_json_unref);
Expand Down Expand Up @@ -1738,6 +1796,7 @@ static int unload_module(void)
AST_TEST_UNREGISTER(json_test_object_null);
AST_TEST_UNREGISTER(json_test_object_iter);
AST_TEST_UNREGISTER(json_test_object_iter_null);
AST_TEST_UNREGISTER(json_test_object_create_vars);
AST_TEST_UNREGISTER(json_test_dump_load_string);
AST_TEST_UNREGISTER(json_test_dump_load_str);
AST_TEST_UNREGISTER(json_test_dump_str_fail);
Expand Down Expand Up @@ -1794,6 +1853,7 @@ static int load_module(void)
AST_TEST_REGISTER(json_test_object_null);
AST_TEST_REGISTER(json_test_object_iter);
AST_TEST_REGISTER(json_test_object_iter_null);
AST_TEST_REGISTER(json_test_object_create_vars);
AST_TEST_REGISTER(json_test_dump_load_string);
AST_TEST_REGISTER(json_test_dump_load_str);
AST_TEST_REGISTER(json_test_dump_str_fail);
Expand Down
116 changes: 116 additions & 0 deletions tests/test_strings.c
Original file line number Diff line number Diff line change
Expand Up @@ -620,6 +620,120 @@ AST_TEST_DEFINE(temp_strings)
return AST_TEST_PASS;
}

AST_TEST_DEFINE(in_delimited_string)
{
switch (cmd) {
case TEST_INIT:
info->name = "in_delimited_string";
info->category = "/main/strings/";
info->summary = "Test ast_in_delimited_string";
info->description = info->summary;
return AST_TEST_NOT_RUN;
case TEST_EXECUTE:
break;
}

/* Single letter */
ast_test_validate(test, ast_in_delimited_string("a", "a,b", ','));
ast_test_validate(test, ast_in_delimited_string("b", "a,b", ','));

ast_test_validate(test, !ast_in_delimited_string("c", "a,b", ','));
ast_test_validate(test, !ast_in_delimited_string("aa", "a,b", ','));
ast_test_validate(test, !ast_in_delimited_string("bb", "a,b", ','));
ast_test_validate(test, !ast_in_delimited_string("a,", "a,b", ','));
ast_test_validate(test, !ast_in_delimited_string(",b", "a,b", ','));
ast_test_validate(test, !ast_in_delimited_string("a,b", "a,b", ','));

/* Bad delimiter (ends up being just a strcmp) */
ast_test_validate(test, !ast_in_delimited_string("a", "a,b", '#'));
ast_test_validate(test, !ast_in_delimited_string("b", "a,b", '#'));

ast_test_validate(test, !ast_in_delimited_string("c", "a,b", '#'));
ast_test_validate(test, !ast_in_delimited_string("aa", "a,b", '#'));
ast_test_validate(test, !ast_in_delimited_string("bb", "a,b", '#'));
ast_test_validate(test, !ast_in_delimited_string("a,", "a,b", '#'));
ast_test_validate(test, !ast_in_delimited_string(",b", "a,b", '#'));

ast_test_validate(test, ast_in_delimited_string("a,b", "a,b", '#'));

/* Multi letter */
ast_test_validate(test, ast_in_delimited_string("abc", "abc,def", ','));
ast_test_validate(test, ast_in_delimited_string("def", "abc,def", ','));

ast_test_validate(test, !ast_in_delimited_string("a", "abc,def", ','));
ast_test_validate(test, !ast_in_delimited_string("b", "abc,def", ','));
ast_test_validate(test, !ast_in_delimited_string("c", "abc,def", ','));

ast_test_validate(test, !ast_in_delimited_string("d", "abc,def", ','));
ast_test_validate(test, !ast_in_delimited_string("e", "abc,def", ','));
ast_test_validate(test, !ast_in_delimited_string("f", "abc,def", ','));

ast_test_validate(test, !ast_in_delimited_string("abc,", "abc,def", ','));
ast_test_validate(test, !ast_in_delimited_string(",def", "abc,def", ','));
ast_test_validate(test, !ast_in_delimited_string("abc,def", "abc,def", ','));

/* Embedded */
ast_test_validate(test, ast_in_delimited_string("abc", "abcdef,abc", ','));
ast_test_validate(test, ast_in_delimited_string("abcdef", "abcdef,abc", ','));

ast_test_validate(test, !ast_in_delimited_string("abc", "abcdef,def", ','));
ast_test_validate(test, !ast_in_delimited_string("def", "abcdef,abc", ','));
ast_test_validate(test, !ast_in_delimited_string("def", "abcdefghi,abc", ','));

/* NULL and empty values */
ast_test_validate(test, !ast_in_delimited_string(NULL, "abc,def", ','));

ast_test_validate(test, ast_in_delimited_string("abc", ",abc,def", ','));
ast_test_validate(test, ast_in_delimited_string("abc", "abc,def,", ','));
ast_test_validate(test, ast_in_delimited_string("abc", "abc,,def,", ','));
ast_test_validate(test, ast_in_delimited_string("def", "abc,,def", ','));
ast_test_validate(test, ast_in_delimited_string("def", ",abc,,def,", ','));

ast_test_validate(test, ast_in_delimited_string("", ",abc,def", ','));
ast_test_validate(test, ast_in_delimited_string("", "abc,def,", ','));
ast_test_validate(test, ast_in_delimited_string("", "abc,,def,", ','));
ast_test_validate(test, !ast_in_delimited_string("", "abc,def", ','));

/* Multi word */
ast_test_validate(test, ast_in_delimited_string("abc", "abc,def,ghi", ','));
ast_test_validate(test, ast_in_delimited_string("def", "abc,def,ghi", ','));
ast_test_validate(test, ast_in_delimited_string("ghi", "abc,def,ghi", ','));

ast_test_validate(test, !ast_in_delimited_string("a", "abc,def,ghi", ','));
ast_test_validate(test, !ast_in_delimited_string("d", "abc,def,ghi", ','));
ast_test_validate(test, !ast_in_delimited_string("g", "abc,def,ghi", ','));

ast_test_validate(test, !ast_in_delimited_string("ab", "abc,def,ghi", ','));
ast_test_validate(test, !ast_in_delimited_string("de", "abc,def,ghi", ','));
ast_test_validate(test, !ast_in_delimited_string("gh", "abc,def,ghi", ','));


/* With leading spaces */
ast_test_validate(test, ast_in_delimited_string("abc", " abc", ','));
ast_test_validate(test, ast_in_delimited_string("abc", " abc, def", ','));
ast_test_validate(test, ast_in_delimited_string("def", " abc, def", ','));
ast_test_validate(test, ast_in_delimited_string("abc", " abc, def, ghi", ','));
ast_test_validate(test, ast_in_delimited_string("def", " abc, def, ghi", ','));
ast_test_validate(test, ast_in_delimited_string("ghi", " abc, def, ghi", ','));

ast_test_validate(test, ast_in_delimited_string("abc", " abc", ','));
ast_test_validate(test, ast_in_delimited_string("abc", " abc, def", ','));
ast_test_validate(test, ast_in_delimited_string("def", " abc, def", ','));
ast_test_validate(test, ast_in_delimited_string("abc", " abc, def, ghi", ','));
ast_test_validate(test, ast_in_delimited_string("def", " abc, def, ghi", ','));
ast_test_validate(test, ast_in_delimited_string("ghi", " abc, def, ghi", ','));

/* With leading spaces and space as a delimiter */
ast_test_validate(test, ast_in_delimited_string("abc", " abc", ' '));
ast_test_validate(test, ast_in_delimited_string("abc", " abc def", ' '));
ast_test_validate(test, ast_in_delimited_string("def", " abc def", ' '));
ast_test_validate(test, ast_in_delimited_string("abc", " abc def ghi", ' '));
ast_test_validate(test, ast_in_delimited_string("def", " abc def ghi", ' '));
ast_test_validate(test, ast_in_delimited_string("ghi", " abc def ghi", ' '));

return AST_TEST_PASS;
}

static int unload_module(void)
{
AST_TEST_UNREGISTER(str_test);
Expand All @@ -630,6 +744,7 @@ static int unload_module(void)
AST_TEST_UNREGISTER(escape_test);
AST_TEST_UNREGISTER(strings_match);
AST_TEST_UNREGISTER(temp_strings);
AST_TEST_UNREGISTER(in_delimited_string);
return 0;
}

Expand All @@ -643,6 +758,7 @@ static int load_module(void)
AST_TEST_REGISTER(escape_test);
AST_TEST_REGISTER(strings_match);
AST_TEST_REGISTER(temp_strings);
AST_TEST_REGISTER(in_delimited_string);
return AST_MODULE_LOAD_SUCCESS;
}

Expand Down

0 comments on commit 67d1f88

Please sign in to comment.