
On 02/19/2014 09:36 PM, Daniel P. Berrange wrote:
From: Manuel VIVES <manuel.vives@diateam.net>
Add a virStringSearch method to virstring.{c,h} which performs a regex match against a string and returns the matching substrings.
Signed-off-by: Daniel P. Berrange <berrange@redhat.com> --- po/POTFILES.in | 1 + src/libvirt_private.syms | 1 + src/util/virstring.c | 102 +++++++++++++++++++++++++++++++++++++++++++++++ src/util/virstring.h | 7 ++++ tests/virstringtest.c | 100 ++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 211 insertions(+)
@@ -645,3 +647,103 @@ int virStringSortRevCompare(const void *a, const void *b)
return strcmp(*sb, *sa); } + +/** + * virStringSearch: + * @str: string to search + * @regexp: POSIX Extended regular expression pattern used for matching + * @max_matches: maximum number of substrings to return + * @result: pointer to an array to be filled with NULL terminated list of matches + * + * Performs a POSIX extended regex search against a string and return all matching substrings. + * The @result value should be freed with virStringFreeList() when no longer
Double space before 'virStringFreeList'.
+ * required. + * + * @code + * char *source = "6853a496-1c10-472e-867a-8244937bd6f0 + * 773ab075-4cd7-4fc2-8b6e-21c84e9cb391 + * bbb3c75c-d60f-43b0-b802-fd56b84a4222 + * 60c04aa1-0375-4654-8d9f-e149d9885273 + * 4548d465-9891-4c34-a184-3b1c34a26aa8"; + * char **matches = NULL; + * virSearchRegex(source,
The function is now renamed.
+ * "([a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12})", + * 3, + * &matches); + * + * // matches[0] == "4548d465-9891-4c34-a184-3b1c34a26aa8"; + * // matches[1] == "6853a496-1c10-472e-867a-8244937bd6f0"; + * // matches[2] == "773ab075-4cd7-4fc2-8b6e-21c84e9cb391" + * // matches[3] == NULL;
And these matches are wrong.
+ * + * virStringFreeList(matches); + * @endcode + * + * Returns: -1 on error, or number of matches + */ +ssize_t +virStringSearch(const char *str, + const char *regexp, + size_t max_matches, + char ***matches) +{ + regex_t re; + regmatch_t rem; + size_t nmatches = 0; + ssize_t ret = -1; + int rv = -1; + + *matches = NULL; + + VIR_DEBUG("search '%s' for '%s'", str, regexp); + + if ((rv = regcomp(&re, regexp, REG_EXTENDED)) != 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Error while compiling regular expression '%s': %d"), + regexp, rv);
Using 'regerror' instead of a numeric error code would be nicer.
+ return -1; + } + + if (re.re_nsub != 1) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Regular expression '%s' must have exactly 1 match group, not %zu"), + regexp, re.re_nsub); + goto cleanup; + } + + /* '*matches' must always be NULL terminated in every iteration + * of the loop, so start by allocating 1 element + */ + if (VIR_EXPAND_N(*matches, nmatches, 1) < 0) + goto cleanup; +
diff --git a/tests/virstringtest.c b/tests/virstringtest.c index c6adf9f..b8c6115 100644 --- a/tests/virstringtest.c +++ b/tests/virstringtest.c @@ -274,6 +274,70 @@ testStringSortCompare(const void *opaque ATTRIBUTE_UNUSED) }
+struct stringSearchData { + const char *str; + const char *regexp; + size_t maxMatches; + size_t expectNMatches; + const char **expectMatches; + bool expectError; +}; + +static int +testStringSearch(const void *opaque ATTRIBUTE_UNUSED) +{ + const struct stringSearchData *data = opaque; + char **matches = NULL; + ssize_t nmatches; + int ret;
ret = -1; ACK with or without regerror. Jan