diff options
Diffstat (limited to 'usr/src/lib/libcmdutils/common/custr.c')
-rw-r--r-- | usr/src/lib/libcmdutils/common/custr.c | 87 |
1 files changed, 71 insertions, 16 deletions
diff --git a/usr/src/lib/libcmdutils/common/custr.c b/usr/src/lib/libcmdutils/common/custr.c index 1ec72de9dd..03a9561934 100644 --- a/usr/src/lib/libcmdutils/common/custr.c +++ b/usr/src/lib/libcmdutils/common/custr.c @@ -20,13 +20,20 @@ #include <stdlib.h> #include <err.h> #include <string.h> +#include <stdio.h> +#include <stdarg.h> #include "libcmdutils.h" +typedef enum { + CUSTR_FIXEDBUF = 0x01 +} custr_flags_t; + struct custr { size_t cus_strlen; size_t cus_datalen; char *cus_data; + custr_flags_t cus_flags; }; #define STRING_CHUNK_SIZE 64 @@ -53,23 +60,15 @@ custr_cstr(custr_t *cus) return (cus->cus_data); } -int -custr_appendc(custr_t *cus, char newc) -{ - char news[2]; - - news[0] = newc; - news[1] = '\0'; - - return (custr_append(cus, news)); -} - -int -custr_append(custr_t *cus, const char *news) +static int +custr_append_vprintf(custr_t *cus, const char *fmt, va_list ap) { - size_t len = strlen(news); + int len = vsnprintf(NULL, 0, fmt, ap); size_t chunksz = STRING_CHUNK_SIZE; + if (len == -1) + return (len); + while (chunksz < len) { chunksz *= 2; } @@ -78,6 +77,11 @@ custr_append(custr_t *cus, const char *news) char *new_data; size_t new_datalen = cus->cus_datalen + chunksz; + if (cus->cus_flags & CUSTR_FIXEDBUF) { + errno = EOVERFLOW; + return (-1); + } + /* * Allocate replacement memory: */ @@ -104,13 +108,41 @@ custr_append(custr_t *cus, const char *news) /* * Append new string to existing string: */ - (void) memcpy(cus->cus_data + cus->cus_strlen, news, len + 1); + len = vsnprintf(cus->cus_data + cus->cus_strlen, + (uintptr_t)cus->cus_data - (uintptr_t)cus->cus_strlen, fmt, ap); + if (len == -1) + return (len); cus->cus_strlen += len; return (0); } int +custr_appendc(custr_t *cus, char newc) +{ + return (custr_append_printf(cus, "%c", newc)); +} + +int +custr_append_printf(custr_t *cus, const char *fmt, ...) +{ + va_list ap; + int ret; + + va_start(ap, fmt); + ret = custr_append_vprintf(cus, fmt, ap); + va_end(ap); + + return (ret); +} + +int +custr_append(custr_t *cus, const char *name) +{ + return (custr_append_printf(cus, "%s", name)); +} + +int custr_alloc(custr_t **cus) { custr_t *t; @@ -124,12 +156,35 @@ custr_alloc(custr_t **cus) return (0); } +int +custr_alloc_buf(custr_t **cus, void *buf, size_t buflen) +{ + int ret; + + if (buflen == 0 || buf == NULL) { + errno = EINVAL; + return (-1); + } + + if ((ret = custr_alloc(cus)) != 0) + return (ret); + + (*cus)->cus_data = buf; + (*cus)->cus_datalen = buflen; + (*cus)->cus_strlen = 0; + (*cus)->cus_flags = CUSTR_FIXEDBUF; + (*cus)->cus_data[0] = '\0'; + + return (0); +} + void custr_free(custr_t *cus) { if (cus == NULL) return; - free(cus->cus_data); + if ((cus->cus_flags & CUSTR_FIXEDBUF) == 0) + free(cus->cus_data); free(cus); } |