diff options
Diffstat (limited to 'usr/src/lib/libcmdutils')
-rw-r--r-- | usr/src/lib/libcmdutils/common/custr.c | 100 | ||||
-rw-r--r-- | usr/src/lib/libcmdutils/common/mapfile-vers | 2 | ||||
-rw-r--r-- | usr/src/lib/libcmdutils/libcmdutils.h | 13 |
3 files changed, 98 insertions, 17 deletions
diff --git a/usr/src/lib/libcmdutils/common/custr.c b/usr/src/lib/libcmdutils/common/custr.c index 1ec72de9dd..8da7b98ac2 100644 --- a/usr/src/lib/libcmdutils/common/custr.c +++ b/usr/src/lib/libcmdutils/common/custr.c @@ -14,19 +14,27 @@ */ /* - * Copyright 2014, Joyent, Inc. + * Copyright 2015 Joyent, Inc. */ #include <stdlib.h> #include <err.h> #include <string.h> +#include <stdio.h> +#include <stdarg.h> +#include <sys/debug.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 @@ -50,26 +58,28 @@ custr_len(custr_t *cus) const char * custr_cstr(custr_t *cus) { - return (cus->cus_data); -} + if (cus->cus_data == NULL) { + VERIFY(cus->cus_strlen == 0); + VERIFY(cus->cus_datalen == 0); -int -custr_appendc(custr_t *cus, char newc) -{ - char news[2]; - - news[0] = newc; - news[1] = '\0'; - - return (custr_append(cus, news)); + /* + * This function should never return NULL. If no buffer has + * been allocated, return a pointer to a zero-length string. + */ + return (""); + } + return (cus->cus_data); } -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 +88,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 +119,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 +167,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); } diff --git a/usr/src/lib/libcmdutils/common/mapfile-vers b/usr/src/lib/libcmdutils/common/mapfile-vers index 640959e4b5..3106695eb0 100644 --- a/usr/src/lib/libcmdutils/common/mapfile-vers +++ b/usr/src/lib/libcmdutils/common/mapfile-vers @@ -43,8 +43,10 @@ SYMBOL_VERSION SUNWprivate_1.1 { global: add_tnode; custr_alloc; + custr_alloc_buf; custr_append; custr_appendc; + custr_append_printf; custr_cstr; custr_free; custr_len; diff --git a/usr/src/lib/libcmdutils/libcmdutils.h b/usr/src/lib/libcmdutils/libcmdutils.h index bbc03475dc..e0c97178dc 100644 --- a/usr/src/lib/libcmdutils/libcmdutils.h +++ b/usr/src/lib/libcmdutils/libcmdutils.h @@ -156,6 +156,12 @@ extern int custr_alloc(custr_t **); extern void custr_free(custr_t *); /* + * Allocate a "custr_t" dynamic string object that operates on a fixed external + * buffer. + */ +extern int custr_alloc_buf(custr_t **, void *, size_t); + +/* * Append a single character, or a NUL-terminated string of characters, to a * dynamic string. Returns 0 on success and -1 otherwise. The dynamic string * will be unmodified if the function returns -1. @@ -164,6 +170,13 @@ extern int custr_appendc(custr_t *, char); extern int custr_append(custr_t *, const char *); /* + * Append a format string and arguments as though the contents were being parsed + * through snprintf. Returns 0 on success and -1 otherwise. The dynamic string + * will be unmodified if the function returns -1. + */ +extern int custr_append_printf(custr_t *, const char *, ...); + +/* * Determine the length in bytes, not including the NUL terminator, of the * dynamic string. */ |