summaryrefslogtreecommitdiff
path: root/usr/src/lib/libcmdutils
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/lib/libcmdutils')
-rw-r--r--usr/src/lib/libcmdutils/common/custr.c100
-rw-r--r--usr/src/lib/libcmdutils/common/mapfile-vers2
-rw-r--r--usr/src/lib/libcmdutils/libcmdutils.h13
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.
*/