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

Daniel P. Berrange berrange at redhat.com
Fri Nov 30 18:57:49 UTC 2012


On Fri, Nov 30, 2012 at 11:02:40AM -0500, Eric Blake wrote:
> > 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 **
> 
> Do we also want to migrate virsh.c:vshStringToArray() to
> this file, with its additional magic of supporting ',,'
> as an escape sequence for literal comma in one of the
> strings being split?

I don't really like that magic escape behaviour for a
general purpose string splitting function. IMHO if the
thing being split needs to use ',' then the delimitor
should be changed.

> > +char *virStringJoin(const char **strings,
> > +                    const char *delim)
> > +{
> 
> Should this function have a third argument that says how many
> elements are in strings (and leave it 0 if strings is
> NULL-terminated)?  Otherwise, callers will have to ensure
> that there is a trailing NULL element in strings, instead
> of being able to specifically request the joining of an
> exact amount of strings.

I don't much like the idea of having one API that deals
with two different ways of representing the array bounds.

If we want explicited sized arrays, I think it'd be nicer
to have a parallel set of APIs todo that (albeit sharing
internal impl where appropriate)

> > +    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++;
> > +    }
> 
> Would it be any easier to write this function in terms of
> virBuffer, instead of rolling it by hand?  Untested:
> 
> char *virStringJoin(const char **strings,
>                     const char *delim)
> {
>     virBuffer buf = VIR_BUFFER_INITIALIZER;
>     if (strings && *strings) {
>         virBufferAdd(&buf, *strings, 0);
>         while (*++strings) {
>             virBufferAdd(&buf, delim, 0);
>             virBufferAdd(*strings);
>         }
>     }
>     return virBufferContentAndReset(&buf);
> }

I guess there's not much difference in efficiency
there & it is shorter, so why not.


> > +char **virStringSplit(const char *string,
> > +                      const char *delim,
> > +                      size_t max_tokens);
> 
> Worth marking ATTRIBUTE_NONNULL(2)?  It looks like you
> intend to allow NULL for arg 1 though (in which case the
> return is also NULL).

We shouldn't allow NULL for arg 1, since then
a NULL return value can be either an error or
valid, depending on the parameters, which has
unpleasant semantics.

> 

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