[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

[libvirt] [PATCH 1/5] util: virstring: introduce virStrcat and VIR_STRCAT



Signed-off-by: Pavel Hrdina <phrdina redhat com>
---
 cfg.mk                   |  2 +-
 src/libvirt_private.syms |  2 ++
 src/util/virstring.c     | 70 ++++++++++++++++++++++++++++++++++++++++++++++++
 src/util/virstring.h     | 27 +++++++++++++++++++
 tests/virstringtest.c    | 49 +++++++++++++++++++++++++++++++++
 5 files changed, 149 insertions(+), 1 deletion(-)

diff --git a/cfg.mk b/cfg.mk
index aaba61f1dc..22c655eac6 100644
--- a/cfg.mk
+++ b/cfg.mk
@@ -1147,7 +1147,7 @@ exclude_file_name_regexp--sc_prohibit_fork_wrappers = \
 exclude_file_name_regexp--sc_prohibit_gethostname = ^src/util/virutil\.c$$
 
 exclude_file_name_regexp--sc_prohibit_internal_functions = \
-  ^src/(util/(viralloc|virutil|virfile)\.[hc]|esx/esx_vi\.c)$$
+  ^src/(util/(viralloc|virutil|virfile|virstring)\.[hc]|esx/esx_vi\.c)$$
 
 exclude_file_name_regexp--sc_prohibit_newline_at_end_of_diagnostic = \
   ^src/rpc/gendispatch\.pl$$
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 07a35333b1..e9c4d73779 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -2502,6 +2502,8 @@ virAsprintfInternal;
 virSkipSpaces;
 virSkipSpacesAndBackslash;
 virSkipSpacesBackwards;
+virStrcat;
+virStrcatInplace;
 virStrcpy;
 virStrdup;
 virStringBufferIsPrintable;
diff --git a/src/util/virstring.c b/src/util/virstring.c
index 69abc267bf..bc15ce7e9e 100644
--- a/src/util/virstring.c
+++ b/src/util/virstring.c
@@ -837,6 +837,76 @@ virStrndup(char **dest,
 }
 
 
+/**
+ * virStrcat
+ * @dest: where to store concatenated string
+ * @src: the source string to append to @dest
+ * @inPlace: false if we should expand the allocated memory before moving,
+ *           true if we should assume someone else has already done that.
+ * @report: whether to report OOM error, if there is one
+ * @domcode: error domain code
+ * @filename: caller's filename
+ * @funcname: caller's funcname
+ * @linenr: caller's line number
+ *
+ * Wrapper over strcat, which reports OOM error if told so,
+ * in which case callers wants to pass @domcode, @filename,
+ * @funcname and @linenr which should represent location in
+ * caller's body where virStrcat is called from. Consider
+ * using VIR_STRCAT which sets these automatically.
+ *
+ * Returns: 0 for NULL src, 1 on successful concatenate, -1 otherwise.
+ */
+int
+virStrcat(char **dest,
+          const char *src,
+          bool report,
+          int domcode,
+          const char *filename,
+          const char *funcname,
+          size_t linenr)
+{
+    size_t dest_len = 0;
+    size_t src_len = 0;
+
+    if (!src)
+        return 0;
+
+    if (*dest)
+        dest_len = strlen(*dest);
+    src_len = strlen(src);
+
+    if (virReallocN(dest, sizeof(*dest), dest_len + src_len + 1,
+                    report, domcode, filename, funcname, linenr) < 0)
+        return -1;
+
+    strcat(*dest, src);
+
+    return 1;
+}
+
+
+/**
+ * virStrcat
+ * @dest: where to store concatenated string
+ * @src: the source string to append to @dest
+ *
+ * Wrapper over strcat, which properly handles if @src is NULL.
+ *
+ * Returns: 0 for NULL src, 1 on successful concatenate.
+ */
+int
+virStrcatInplace(char *dest, const char *src)
+{
+    if (!src)
+        return 0;
+
+    strcat(dest, src);
+
+    return 1;
+}
+
+
 size_t virStringListLength(const char * const *strings)
 {
     size_t i = 0;
diff --git a/src/util/virstring.h b/src/util/virstring.h
index a5550e30d2..79d2f23c80 100644
--- a/src/util/virstring.h
+++ b/src/util/virstring.h
@@ -131,6 +131,13 @@ int virStrdup(char **dest, const char *src, bool report, int domcode,
 int virStrndup(char **dest, const char *src, ssize_t n, bool report, int domcode,
                const char *filename, const char *funcname, size_t linenr)
     ATTRIBUTE_RETURN_CHECK ATTRIBUTE_NONNULL(1);
+
+int virStrcat(char **dest, const char *src, bool report, int domcode,
+              const char *filename, const char *funcname, size_t linenr)
+    ATTRIBUTE_RETURN_CHECK ATTRIBUTE_NONNULL(1);
+int virStrcatInplace(char *dest, const char *src)
+    ATTRIBUTE_NONNULL(1);
+
 int virAsprintfInternal(bool report, int domcode, const char *filename,
                         const char *funcname, size_t linenr, char **strp,
                         const char *fmt, ...)
@@ -209,6 +216,26 @@ int virVasprintfInternal(bool report, int domcode, const char *filename,
 # define VIR_STRNDUP_QUIET(dst, src, n) virStrndup(&(dst), src, n, false, \
                                                    0, NULL, NULL, 0)
 
+/**
+ * VIR_STRCAT:
+ * @dst: variable to hold result (char*, not char**)
+ * @src: string to concatenate to @dst
+ *
+ * Concatenate @src string into @dst string, @dst may be NULL.
+ *
+ * This macro is safe to use on arguments with side effects.
+ *
+ * VIR_STRCAT_INPLACE expect the @dst to be already allocated to hold
+ * the result.
+ *
+ * Returns -1 on failure, 0 if @src was NULL, 1 if @src was concatenated.
+ */
+# define VIR_STRCAT(dst, src) virStrcat(&(dst), src, true, VIR_FROM_THIS, \
+                                        __FILE__, __FUNCTION__, __LINE__)
+# define VIR_STRCAT_QUIET(dst, src) virStrcat(&(dst), src, false, 0, \
+                                              NULL, NULL, 0)
+# define VIR_STRCAT_INPLACE(dst, src) virStrcatInplace(dst, src)
+
 size_t virStringListLength(const char * const *strings);
 
 /**
diff --git a/tests/virstringtest.c b/tests/virstringtest.c
index db1731f96a..d2d6138326 100644
--- a/tests/virstringtest.c
+++ b/tests/virstringtest.c
@@ -693,6 +693,37 @@ static int testStripControlChars(const void *args)
     return ret;
 }
 
+
+struct testStrcatData {
+    const char *dest;
+    const char *src;
+    const char *res;
+};
+
+static int
+testStrcat(const void *args)
+{
+    const struct testStrcatData *data = args;
+    char *str = NULL;
+    int ret = -1;
+
+    if (VIR_STRDUP(str, data->dest) < 0)
+        goto cleanup;
+
+    if (VIR_STRCAT(str, data->src) < 0)
+        goto cleanup;
+
+    if (!STREQ_NULLABLE(str, data->res))
+        goto cleanup;
+
+    ret = 0;
+
+ cleanup:
+    VIR_FREE(str);
+    return ret;
+}
+
+
 static int
 mymain(void)
 {
@@ -958,6 +989,24 @@ mymain(void)
     TEST_STRIP_CONTROL_CHARS("\x01H\x02" "E\x03L\x04L\x05O", "HELLO");
     TEST_STRIP_CONTROL_CHARS("\x01\x02\x03\x04HELL\x05O", "HELLO");
     TEST_STRIP_CONTROL_CHARS("\nhello \x01\x07hello\t", "\nhello hello\t");
+
+#define TEST_STRCAT(dests, srcs, ress)                                      \
+    do {                                                                    \
+        struct testStrcatData strcatData = {                                \
+            .dest = dests,                                                  \
+            .src = srcs,                                                    \
+            .res = ress,                                                    \
+        };                                                                  \
+        if (virTestRun("Concatenate '" #dests "' with '" #srcs "'",         \
+                       testStrcat, &strcatData) < 0)                        \
+            ret = -1;                                                       \
+    } while (0)
+
+    TEST_STRCAT(NULL, NULL, NULL);
+    TEST_STRCAT(NULL, "world", "world");
+    TEST_STRCAT("hello", NULL, "hello");
+    TEST_STRCAT("hello", "world", "helloworld");
+
     return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
 }
 
-- 
2.11.1


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]