From c1e2da80dfa62793ea107cf12408c814e268a54b Mon Sep 17 00:00:00 2001 From: Vincent Sanders Date: Sun, 4 May 2014 18:29:53 +0100 Subject: add string utility to join strings --- utils/errors.h | 4 ++- utils/utils.c | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ utils/utils.h | 46 ++++++++++++++++++++++++++++++++++ 3 files changed, 128 insertions(+), 1 deletion(-) diff --git a/utils/errors.h b/utils/errors.h index 4c02adb2d..bfb659d03 100644 --- a/utils/errors.h +++ b/utils/errors.h @@ -73,7 +73,9 @@ typedef enum { NSERROR_FRAME_DEPTH, /**< Exceeded frame depth */ - NSERROR_PERMISSION /**< Permission error */ + NSERROR_PERMISSION, /**< Permission error */ + + NSERROR_NOSPACE /**< Insufficient space */ } nserror; #endif diff --git a/utils/utils.c b/utils/utils.c index 8cb1987d4..bb30f921e 100644 --- a/utils/utils.c +++ b/utils/utils.c @@ -160,6 +160,85 @@ bool is_dir(const char *path) return S_ISDIR(s.st_mode) ? true : false; } +/* exported interface documented in utils/utils.h */ +nserror vsnstrjoin(char **str, size_t *size, char sep, size_t nelm, va_list ap) +{ + const char *elm[16]; + size_t elm_len[16]; + size_t elm_idx; + char *fname; + size_t fname_len = 0; + char *curp; + + /* check the parameters are all sensible */ + if ((nelm == 0) || (nelm > 16)) { + return NSERROR_BAD_PARAMETER; + } + if ((*str != NULL) && (size == NULL)) { + /* if the caller is providing the buffer they must say + * how much space is available. + */ + return NSERROR_BAD_PARAMETER; + } + + /* calculate how much storage we need for the complete path + * with all the elements. + */ + for (elm_idx = 0; elm_idx < nelm; elm_idx++) { + elm[elm_idx] = va_arg(ap, const char *); + elm_len[elm_idx] = strlen(elm[elm_idx]); + fname_len += elm_len[elm_idx]; + } + fname_len += nelm; /* allow for separators and terminator */ + + /* ensure there is enough space */ + fname = *str; + if (fname != NULL) { + if (fname_len > *size) { + return NSERROR_NOSPACE; + } + } else { + fname = malloc(fname_len); + if (fname == NULL) { + return NSERROR_NOMEM; + } + } + + /* copy the elements in with apropriate separator */ + curp = fname; + for (elm_idx = 0; elm_idx < nelm; elm_idx++) { + memmove(curp, elm[elm_idx], elm_len[elm_idx]); + curp += elm_len[elm_idx]; + /* ensure string are separated */ + if (curp[-1] != sep) { + *curp = sep; + curp++; + } + } + curp[-1] = 0; /* NULL terminate */ + + assert((curp - fname) <= (int)fname_len); + + *str = fname; + if (size != NULL) { + *size = fname_len; + } + + return NSERROR_OK; +} + +/* exported interface documented in utils/utils.h */ +nserror snstrjoin(char **str, size_t *size, char sep, size_t nelm, ...) +{ + va_list ap; + nserror ret; + + va_start(ap, nelm); + ret = vsnstrjoin(str, size, sep, nelm, ap); + va_end(ap); + + return ret; +} /** * Compile a regular expression, handling errors. diff --git a/utils/utils.h b/utils/utils.h index db26ed176..33cb0e99a 100644 --- a/utils/utils.h +++ b/utils/utils.h @@ -28,6 +28,9 @@ #include #include #include +#include + +#include "utils/errors.h" struct dirent; @@ -145,6 +148,49 @@ char *human_friendly_bytesize(unsigned long bytesize); const char *rfc1123_date(time_t t); unsigned int wallclock(void); +/** + * Generate a string from one or more component elemnts separated with + * a single value. + * + * This is similar in intent to the perl join function creating a + * single delimited string from an array of several. + * + * @note If a string is allocated it must be freed by the caller. + * + * @param[in,out] str pointer to string pointer if this is NULL enough + * storage will be allocated for the complete path. + * @param[in,out] size The size of the space available if \a str not + * NULL on input and if not NULL set to the total + * output length on output. + * @param[in] sep The character to separete the elemnts with. + * @param[in] nemb The number of elements up to a maximum of 16. + * @param[in] ap The elements of the path as string pointers. + * @return NSERROR_OK and the complete path is written to str or error + * code on faliure. + */ +nserror vsnstrjoin(char **str, size_t *size, char sep, size_t nelm, va_list ap); + +/** + * Generate a string from one or more component elemnts separated with + * a single value. + * + * This is similar in intent to the perl join function creating a + * single delimited string from an array of several. + * + * @note If a string is allocated it must be freed by the caller. + * + * @param[in,out] str pointer to string pointer if this is NULL enough + * storage will be allocated for the complete path. + * @param[in,out] size The size of the space available if \a str not + * NULL on input and if not NULL set to the total + * output length on output. + * @param[in] sep The character to separete the elemnts with. + * @param[in] nemb The number of elements up to a maximum of 16. + * @param[in] ... The elements of the path as string pointers. + * @return NSERROR_OK and the complete path is written to str or error + * code on faliure. + */ +nserror snstrjoin(char **str, size_t *size, char sep, size_t nelm, ...); /** * Comparison function for sorting directories. -- cgit v1.2.3