On 02/19/2014 09:36 PM, Daniel P. Berrange wrote:
From: Manuel VIVES <manuel.vives(a)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(a)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