From 5bf6a1479c2481ac4e3b0b1dea847e37b2782ebd Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Fri, 19 Oct 2018 12:28:38 -0700 Subject: [PATCH] GUACAMOLE-637: Add convenience function for joining an array of strings using a given delimiter. --- src/libguac/guacamole/string.h | 48 ++++++++++++++++++++++++++++++++++ src/libguac/string.c | 24 +++++++++++++++++ 2 files changed, 72 insertions(+) diff --git a/src/libguac/guacamole/string.h b/src/libguac/guacamole/string.h index b3a89c9c..479a8052 100644 --- a/src/libguac/guacamole/string.h +++ b/src/libguac/guacamole/string.h @@ -103,5 +103,53 @@ size_t guac_strlcpy(char* restrict dest, const char* restrict src, size_t n); */ size_t guac_strlcat(char* restrict dest, const char* restrict src, size_t n); +/** + * Concatenates each of the given strings, separated by the given delimiter, + * storing the result within a destination buffer. The number of bytes written + * will be no more than the given number of bytes, and the destination buffer + * is guaranteed to be null-terminated, even if doing so means that one or more + * of the intended strings are truncated or omitted from the end of the result, + * unless the destination buffer has no space available at all. As this + * function always returns the length of the string it tried to create (the + * length of all source strings and all delimiters added together), whether + * truncation has occurred can be detected by comparing the return value + * against the size of the destination buffer. If the value returned is greater + * than or equal to the size of the destination buffer, then the string has + * been truncated. + * + * The source strings, delimiter string, and destination buffer MAY NOT + * overlap. + * + * @param dest + * The buffer which should receive the result of joining the given strings. + * This buffer will always be null terminated unless zero bytes are + * available within the buffer. + * + * @param elements + * The elements to concatenate together, separated by the given delimiter. + * Each element MUST be null-terminated. + * + * @param nmemb + * The number of elements within the elements array. + * + * @param delim + * The delimiter to include between each pair of elements. + * + * @param n + * The number of bytes available within the destination buffer. If this + * value is not greater than zero, no bytes will be written to the + * destination buffer, and the destination buffer may not be null + * terminated. In all other cases, the destination buffer will always be + * null terminated, even if doing so means that the result will be + * truncated. + * + * @return + * The length of the string this function tried to create (the length of + * all source strings and all delimiters added together) in bytes, + * excluding the null terminator. + */ +size_t guac_strljoin(char* restrict dest, const char* restrict const* elements, + int nmemb, const char* restrict delim, size_t n); + #endif diff --git a/src/libguac/string.c b/src/libguac/string.c index 879c5267..c913b4a4 100644 --- a/src/libguac/string.c +++ b/src/libguac/string.c @@ -61,3 +61,27 @@ size_t guac_strlcat(char* restrict dest, const char* restrict src, size_t n) { } +size_t guac_strljoin(char* restrict dest, const char* restrict const* elements, + int nmemb, const char* restrict delim, size_t n) { + + int length = 0; + const char* restrict const* current = elements; + + /* If no elements are provided, nothing to do but ensure the destination + * buffer is null terminated */ + if (nmemb <= 0) + return guac_strlcpy(dest, "", n); + + /* Initialize destination buffer with first element */ + length += guac_strlcpy(dest, *current, n); + + /* Copy all remaining elements, separated by delimiter */ + for (current++; nmemb > 1; current++, nmemb--) { + length += guac_strlcat(dest + length, delim, n - length); + length += guac_strlcat(dest + length, *current, n - length); + } + + return length; + +} +