summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorDennis Camera <skonfig@dtnr.ch>2022-08-20 23:10:27 +0200
committerDennis Camera <skonfig@dtnr.ch>2022-08-20 23:10:27 +0200
commitc3236907ef834555e460daea38369a4874ae5d5d (patch)
tree2c20d69002d7018e10962a1991ff687d9298647c /src
parent33c1ce5e7d72dd48b6b4c59ed085f27998173a5d (diff)
downloadskonfig-c-c3236907ef834555e460daea38369a4874ae5d5d.tar.gz
skonfig-c-c3236907ef834555e460daea38369a4874ae5d5d.zip
[src/util/string.c] Add _r variants for strjoin functions
Diffstat (limited to 'src')
-rw-r--r--src/util/string.c133
-rw-r--r--src/util/string.h74
2 files changed, 144 insertions, 63 deletions
diff --git a/src/util/string.c b/src/util/string.c
index 2b24f4e..d5ad73b 100644
--- a/src/util/string.c
+++ b/src/util/string.c
@@ -20,92 +20,103 @@ char *strdup(const char *s) {
}
#endif
-char *stranjoin(char sep, const char *a[], size_t nmemb) {
- char *dst;
+size_t stranjoin_r(
+ char *restrict buf, size_t buflen, char sep, const char *restrict a[],
+ size_t nmemb) {
+ size_t len = 0;
+
+ if (NULL != buf && 0 < buflen) {
+ /* clear buf string */
+ *buf = '\0';
+ }
- if (nmemb > 0) {
- /* determine length of joined string */
- size_t len = 0;
- for (size_t i = 0; i < nmemb; i++) {
- len += strlen(a[i]) + 1;
+ for (size_t i = 0; i < nmemb; ++i) {
+ if (0 < len) {
+ /* add separator */
+ if (NULL != buf && len < buflen) {
+ *(buf+len) = sep;
+ }
+ ++len;
}
- /* then, join strings */
- dst = calloc(len, sizeof(char));
- if (!dst) {
- return NULL;
+ if (NULL != buf) {
+ /* append element */
+ strncpy(buf+len, a[i], (buflen - len));
}
+ len += strlen(a[i]);
+ }
- char *p = dst;
- for (size_t i = 0; i < nmemb; i++) {
- if (i > 0)
- *p++ = sep;
- size_t l = strlen(a[i]);
- memcpy(p, a[i], l);
- p += l;
- }
+ return len;
+}
+
+char *stranjoin(char sep, const char *a[], size_t nmemb) {
+ /* determine length of result string */
+ size_t len = stranjoin_r(NULL, 0, sep, a, nmemb);
- *p = '\0';
- } else {
- dst = strdup("");
+ /* allocate destination buffer */
+ char *dest = malloc(len+1);
+ if (NULL != dest) {
+ (void)stranjoin_r(dest, len+1, sep, a, nmemb);
}
- return dst;
+ return dest;
}
-char *_strjoin(char sep, /* const char * */...) {
+size_t _vstrjoin_r(char *restrict buf, size_t buflen, char sep, va_list ap) {
const char *s;
- char *dst, *p;
- va_list ap;
- size_t len, l;
-
- va_start(ap, sep);
+ size_t len = 0;
- s = va_arg(ap, const char *);
-
- if (s) {
- /* determine length of joined string */
- len = strlen(s) + 1;
+ if (NULL != buf && 0 < buflen) {
+ /* clear buf string */
+ *buf = '\0';
+ }
- while ((s = va_arg(ap, const char *))) {
- len += strlen(s) + 1;
+ while (NULL != (s = va_arg(ap, const char *restrict))) {
+ if (0 < len) {
+ /* add separator */
+ if (NULL != buf && len < buflen) {
+ *(buf+len) = sep;
+ }
+ ++len;
}
- va_end(ap);
- /* Then, join strings */
- dst = calloc(len, sizeof(char));
- if (!dst) {
- return NULL;
+ if (NULL != buf) {
+ /* append element */
+ strncpy(buf+len, s, (buflen - len));
}
- p = dst;
+ len += strlen(s);
+ }
- va_start(ap, sep);
+ return len;
+}
- /* copy first element */
- s = va_arg(ap, const char *);
- l = strlen(s);
- strcpy(dst, s);
- p += l;
+size_t _strjoin_r(
+ char *restrict buf, size_t buflen, char sep, /* const char *restrict */...) {
+ va_list ap;
+ va_start(ap, sep);
+ size_t len = _vstrjoin_r(buf, buflen, sep, ap);
+ va_end(ap);
+ return len;
+}
- /* then the others */
- while ((s = va_arg(ap, const char *))) {
- l = strlen(s);
+char *_strjoin(char sep, /* const char *restrict */...) {
+ va_list ap;
- *p++ = sep;
- strncpy(p, s, l);
- p += l;
- }
+ /* determine length of result string */
+ va_start(ap, sep);
+ size_t len = _vstrjoin_r(NULL, 0, sep, ap);
+ va_end(ap);
- *p = '\0';
- } else {
- dst = strdup("");
+ /* allocate destination buffer */
+ char *dest = malloc(len+1);
+ if (NULL != dest) {
+ (void)_vstrjoin_r(dest, len+1, sep, ap);
}
- va_end(ap);
-
- return dst;
+ return dest;
}
+
size_t strsplit(const char *restrict in, const char *restrict sep, void *buf) {
size_t i = 0;
char **arr = buf;
diff --git a/src/util/string.h b/src/util/string.h
index c244a29..1ef07d1 100644
--- a/src/util/string.h
+++ b/src/util/string.h
@@ -54,6 +54,25 @@ char *strdup(const char *s);
#define strajoin(sep, a) stranjoin(sep, a, anullidx((void *)a))
/**
+ * strajoin_r:
+ * Joins a C string array using a separator character into a caller allocated
+ * buffer.
+ *
+ * NOTE: the return value of this function is the length of the result if the
+ * buffer would’ve been large enough. Use this to check for truncation.
+ * If the destination buffer wasn’t large enough, the resulting string won’t be
+ * NUL terminated.
+ *
+ * @param buf: the destination buffer (nothing will be written to it if NULL)
+ * @param buflen: the length of @buf
+ * @param sep: a char to insert between eaach element of the array
+ * @param a: the array to join (NULL terminated)
+ * @return the length of the full result string
+ */
+#define strajoin_r(buf, buflen, sep, a, nmemb) \
+ stranjoin_r(buf, buflen, sep, a, anullidx((void *)a))
+
+/**
* stranjoin:
* Joins a C string array using a separator character.
*
@@ -61,12 +80,37 @@ char *strdup(const char *s);
*
* @param sep: a char to insert between each element of the array
* @param a: the array to join
- * @param nmemb: the length of the array
+ * @param nmemb: the number of elements of @a
* @return a newly-allocated C string containing all of the elements joined
*/
char *stranjoin(char sep, const char *a[], size_t nmemb);
-char *_strjoin(char sep, /* const char * */...); /* internal */
+/**
+ * stranjoin_r:
+ * Joins a C string array using a separator character into a caller allocated
+ * buffer.
+ *
+ * NOTE: the return value of this function is the length of the result if the
+ * buffer would’ve been large enough. Use this to check for truncation.
+ * If the destination buffer wasn’t large enough, the resulting string won’t be
+ * NUL terminated.
+ *
+ * @param buf: the destination buffer (nothing will be written to it if NULL)
+ * @param buflen: the length of @buf
+ * @param sep: a char to insert between each element of @a
+ * @param a: the array to join (NULL terminated)
+ * @param nmemb: the number of elements of @a
+ * @return the length of the untruncated joined string
+ */
+size_t stranjoin_r(
+ char *restrict buf, size_t buflen, char sep, const char *restrict a[],
+ size_t nmemb);
+
+
+char *_strjoin( /* internal */
+ char sep, /* const char * */...);
+size_t _strjoin_r( /* internal */
+ char *restrict buf, size_t buflen, char sep, /* const char * */...);
/**
* strjoin:
@@ -81,6 +125,19 @@ char *_strjoin(char sep, /* const char * */...); /* internal */
#define strjoin(sep, ...) _strjoin(sep, __VA_ARGS__, NULL)
/**
+ * strjoin_r:
+ * Joins a number of strings together to form one long string stored in a
+ * caller-allocated buffer with the @separator inserted betwween each of them.
+ *
+ * @param buf: the destination buffer (nothing will be written to it if NULL)
+ * @param buflen: the length of @buf
+ * @param sep: a char to insert between each of the strings
+ * @param ...: a list of strings to join
+ * @return the length of the untruncated joined string
+ */
+#define strjoin_r(sep, ...) _strjoin_r(sep, __VA_ARGS__, NULL)
+
+/**
* pathjoin:
* Joins a number of path components together to form one single path.
* The returned string should be free()d.
@@ -91,6 +148,19 @@ char *_strjoin(char sep, /* const char * */...); /* internal */
#define pathjoin(...) strjoin(stringize(DIRSEP)[0], __VA_ARGS__)
/**
+ * pathjoin_r:
+ * Joins a number of path components together to form one single path.
+ * The result is stored in a caller-allocated buffer.
+ *
+ * @param buf: the destination buffer (nothing will be weitten to it if NULL)
+ * @param buflen: the length of @buf
+ * @param ...: a list of path components to join
+ * @return the length of the untruncated joined string
+ */
+#define pathjoin_r(buf, buflen, ...) \
+ strjoin_r(buf, buflen, stringize(DIRSEP)[0], __VA_ARGS__)
+
+/**
* strsplit:
* Splits a string into a NULL-terminated array by a given separator.
*