[libvirt] [PATCH] Introduce APIs for splitting/joining strings

Daniel P. Berrange berrange at redhat.com
Fri Nov 30 15:39:55 UTC 2012


On Fri, Nov 30, 2012 at 03:34:36PM +0000, Daniel P. Berrange wrote:
> From: "Daniel P. Berrange" <berrange at redhat.com>
> 
> This introduces a few new APIs for dealing with strings.
> One to split a char * into a char **, another to join a
> char ** into a char *, and finally one to free a char **
> 
> There is a simple test suite to validate the edge cases
> too. No more need to use the horrible strtok_r() API,
> or hand-written code for splitting strings.
> 
> Signed-off-by: Daniel P. Berrange <berrange at redhat.com>
> ---
>  src/Makefile.am          |   1 +
>  src/libvirt_private.syms |   6 ++
>  src/util/virstring.c     | 129 +++++++++++++++++++++++++++++++++++++
>  src/util/virstring.h     |  36 +++++++++++
>  tests/Makefile.am        |   6 ++
>  tests/virstringtest.c    | 164 +++++++++++++++++++++++++++++++++++++++++++++++
>  6 files changed, 342 insertions(+)
>  create mode 100644 src/util/virstring.c
>  create mode 100644 src/util/virstring.h
>  create mode 100644 tests/virstringtest.c

Opps, the virstring.c file should have this patch spliced in

diff --git a/src/util/virstring.c b/src/util/virstring.c
index 97dddac..fda378a 100644
--- a/src/util/virstring.c
+++ b/src/util/virstring.c
@@ -27,6 +27,35 @@
 
 #define VIR_FROM_THIS VIR_FROM_NONE
 
+/*
+ * The following virStringSplit & virStringJoin methods
+ * are derived from g_strsplit / g_strjoin in glib2,
+ * also available under the LGPLv2+ license terms
+ */
+
+/**
+ * virStringSplit:
+ * @string: a string to split
+ * @delim: a string which specifies the places at which to split
+ *     the string. The delimiter is not included in any of the resulting
+ *     strings, unless @max_tokens is reached.
+ * @max_tokens: the maximum number of pieces to split @string into.
+ *     If this is less than 1, the string is split completely.
+ *
+ * Splits a string into a maximum of @max_tokens pieces, using the given
+ * @delim. If @max_tokens is reached, the remainder of @string is
+ * appended to the last token.
+ *
+ * As a special case, the result of splitting the empty string "" is an empty
+ * vector, not a vector containing a single string. The reason for this
+ * special case is that being able to represent a empty vector is typically
+ * more useful than consistent handling of empty elements. If you do need
+ * to represent empty elements, you'll need to check for the empty string
+ * before calling virStringSplit().
+ *
+ * Return value: a newly-allocated NULL-terminated array of strings. Use
+ *    virStringFreeList() to free it.
+ */
 char **virStringSplit(const char *string,
                       const char *delim,
                       size_t max_tokens)
@@ -83,6 +112,18 @@ no_memory:
 }
 
 
+/**
+ * virStringJoin:
+ * @strings: a NULL-terminated array of strings to join
+ * @delim: a string to insert between each of the strings
+ *
+ * Joins a number of strings together to form one long string, with the
+ * @delim inserted between each of them. The returned string
+ * should be freed with VIR_FREE().
+ *
+ * Returns: a newly-allocated string containing all of the strings joined
+ *     together, with @delim between them
+ */
 char *virStringJoin(const char **strings,
                     const char *delim)
 {
@@ -118,6 +159,13 @@ char *virStringJoin(const char **strings,
 }
 
 
+/**
+ * virStringFreeList:
+ * @str_array: a NULL-terminated array of strings to free
+ *
+ * Frees a NULL-terminated array of strings, and the array itself.
+ * If called on a NULL value, virStringFreeList() simply returns.
+ */
 void virStringFreeList(char **strings)
 {
     char **tmp = strings;


> 
> diff --git a/src/Makefile.am b/src/Makefile.am
> index 6401dec..b5c20c8 100644
> --- a/src/Makefile.am
> +++ b/src/Makefile.am
> @@ -112,6 +112,7 @@ UTIL_SOURCES =							\
>  		util/virnetlink.c util/virnetlink.h		\
>  		util/virrandom.h util/virrandom.c		\
>  		util/virsocketaddr.h util/virsocketaddr.c \
> +		util/virstring.h util/virstring.c \
>  		util/virtime.h util/virtime.c \
>  		util/viruri.h util/viruri.c
>  
> diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
> index 93a21cc..08974d0 100644
> --- a/src/libvirt_private.syms
> +++ b/src/libvirt_private.syms
> @@ -1812,6 +1812,12 @@ virSetErrorLogPriorityFunc;
>  virStrerror;
>  
>  
> +# virstring.h
> +virStringSplit;
> +virStringJoin;
> +virStringFreeList;
> +
> +
>  # virtime.h
>  virTimeFieldsNow;
>  virTimeFieldsNowRaw;
> diff --git a/src/util/virstring.c b/src/util/virstring.c
> new file mode 100644
> index 0000000..97dddac
> --- /dev/null
> +++ b/src/util/virstring.c
> @@ -0,0 +1,129 @@
> +/*
> + * Copyright (C) 2007-2012 Red Hat, Inc.
> + *
> + * This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2.1 of the License, or (at your option) any later version.
> + *
> + * This library is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with this library.  If not, see
> + * <http://www.gnu.org/licenses/>.
> + *
> + * Authors:
> + *     Daniel P. Berrange <berrange at redhat.com>
> + */
> +
> +#include <config.h>
> +
> +#include "virstring.h"
> +#include "memory.h"
> +#include "virterror_internal.h"
> +
> +#define VIR_FROM_THIS VIR_FROM_NONE
> +
> +char **virStringSplit(const char *string,
> +                      const char *delim,
> +                      size_t max_tokens)
> +{
> +    char **tokens = NULL;
> +    size_t ntokens = 0;
> +    size_t maxtokens = 0;
> +    const char *remainder = string;
> +    char *tmp;
> +    size_t i;
> +
> +    if (max_tokens < 1)
> +        max_tokens = INT_MAX;
> +
> +    tmp = strstr(remainder, delim);
> +    if (tmp) {
> +        size_t delimlen = strlen(delim);
> +
> +        while (--max_tokens && tmp) {
> +            size_t len = tmp - remainder;
> +
> +            if (VIR_RESIZE_N(tokens, maxtokens, ntokens, 1) < 0)
> +                goto no_memory;
> +
> +            if (!(tokens[ntokens] = strndup(remainder, len)))
> +                goto no_memory;
> +            ntokens++;
> +            remainder = tmp + delimlen;
> +            tmp = strstr(remainder, delim);
> +        }
> +    }
> +    if (*string) {
> +        if (VIR_RESIZE_N(tokens, maxtokens, ntokens, 1) < 0)
> +            goto no_memory;
> +
> +        if (!(tokens[ntokens] = strdup(remainder)))
> +            goto no_memory;
> +        ntokens++;
> +    }
> +
> +    if (VIR_RESIZE_N(tokens, maxtokens, ntokens, 1) < 0)
> +        goto no_memory;
> +    tokens[ntokens++] = NULL;
> +
> +    return tokens;
> +
> +no_memory:
> +    virReportOOMError();
> +    for (i = 0 ; i < ntokens ; i++) {
> +        VIR_FREE(tokens[i]);
> +    }
> +    VIR_FREE(tokens);
> +    return NULL;
> +}
> +
> +
> +char *virStringJoin(const char **strings,
> +                    const char *delim)
> +{
> +    size_t len = 0;
> +    size_t delimlen = strlen(delim);
> +    const char **tmp = strings;
> +    char *string;
> +    char *offset;
> +
> +    while (tmp && *tmp) {
> +        len += strlen(*tmp);
> +        len += delimlen;
> +        tmp++;
> +    }
> +
> +    if (VIR_ALLOC_N(string, len + 1) < 0) {
> +        virReportOOMError();
> +        return NULL;
> +    }
> +
> +    tmp = strings;
> +    offset = string;
> +    while (tmp && *tmp) {
> +        offset = stpcpy(offset, *tmp);
> +        if (*(tmp+1))
> +            offset = stpcpy(offset, delim);
> +        len += strlen(*tmp);
> +        len += delimlen;
> +        tmp++;
> +    }
> +
> +    return string;
> +}
> +
> +
> +void virStringFreeList(char **strings)
> +{
> +    char **tmp = strings;
> +    while (tmp && *tmp) {
> +        VIR_FREE(*tmp);
> +        tmp++;
> +    }
> +    VIR_FREE(strings);
> +}


Daniel
-- 
|: http://berrange.com      -o-    http://www.flickr.com/photos/dberrange/ :|
|: http://libvirt.org              -o-             http://virt-manager.org :|
|: http://autobuild.org       -o-         http://search.cpan.org/~danberr/ :|
|: http://entangle-photo.org       -o-       http://live.gnome.org/gtk-vnc :|




More information about the libvir-list mailing list