dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / lib / libcmdutils / common / custr.c
blob95d44e431fd4e9f1d63a648b1dc3d0367191706a
1 /*
2 * This file and its contents are supplied under the terms of the
3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 * You may only use this file in accordance with the terms of version
5 * 1.0 of the CDDL.
7 * A full copy of the text of the CDDL should have accompanied this
8 * source. A copy of the CDDL is also available via the Internet at
9 * http://www.illumos.org/license/CDDL.
13 * String utility functions with dynamic memory management.
17 * Copyright 2016 Joyent, Inc.
20 #include <stdlib.h>
21 #include <err.h>
22 #include <string.h>
23 #include <stdio.h>
24 #include <stdarg.h>
25 #include <sys/debug.h>
27 #include "libcmdutils.h"
29 typedef enum {
30 CUSTR_FIXEDBUF = 0x01
31 } custr_flags_t;
33 struct custr {
34 size_t cus_strlen;
35 size_t cus_datalen;
36 char *cus_data;
37 custr_flags_t cus_flags;
40 #define STRING_CHUNK_SIZE 64
42 void
43 custr_reset(custr_t *cus)
45 if (cus->cus_data == NULL)
46 return;
48 cus->cus_strlen = 0;
49 cus->cus_data[0] = '\0';
52 size_t
53 custr_len(custr_t *cus)
55 return (cus->cus_strlen);
58 const char *
59 custr_cstr(custr_t *cus)
61 if (cus->cus_data == NULL) {
62 VERIFY(cus->cus_strlen == 0);
63 VERIFY(cus->cus_datalen == 0);
66 * This function should never return NULL. If no buffer has
67 * been allocated, return a pointer to a zero-length string.
69 return ("");
71 return (cus->cus_data);
74 int
75 custr_append_vprintf(custr_t *cus, const char *fmt, va_list ap)
77 int len = vsnprintf(NULL, 0, fmt, ap);
78 size_t chunksz = STRING_CHUNK_SIZE;
80 if (len == -1)
81 return (len);
83 while (chunksz < len) {
84 chunksz *= 2;
87 if (len + cus->cus_strlen + 1 >= cus->cus_datalen) {
88 char *new_data;
89 size_t new_datalen = cus->cus_datalen + chunksz;
91 if (cus->cus_flags & CUSTR_FIXEDBUF) {
92 errno = EOVERFLOW;
93 return (-1);
97 * Allocate replacement memory:
99 if ((new_data = malloc(new_datalen)) == NULL) {
100 return (-1);
104 * Copy existing data into replacement memory and free
105 * the old memory.
107 if (cus->cus_data != NULL) {
108 (void) memcpy(new_data, cus->cus_data,
109 cus->cus_strlen + 1);
110 free(cus->cus_data);
114 * Swap in the replacement buffer:
116 cus->cus_data = new_data;
117 cus->cus_datalen = new_datalen;
120 * Append new string to existing string:
122 len = vsnprintf(cus->cus_data + cus->cus_strlen,
123 (uintptr_t)cus->cus_data - (uintptr_t)cus->cus_strlen, fmt, ap);
124 if (len == -1)
125 return (len);
126 cus->cus_strlen += len;
128 return (0);
132 custr_appendc(custr_t *cus, char newc)
134 return (custr_append_printf(cus, "%c", newc));
138 custr_append_printf(custr_t *cus, const char *fmt, ...)
140 va_list ap;
141 int ret;
143 va_start(ap, fmt);
144 ret = custr_append_vprintf(cus, fmt, ap);
145 va_end(ap);
147 return (ret);
151 custr_append(custr_t *cus, const char *name)
153 return (custr_append_printf(cus, "%s", name));
157 custr_alloc(custr_t **cus)
159 custr_t *t;
161 if ((t = calloc(1, sizeof (*t))) == NULL) {
162 *cus = NULL;
163 return (-1);
166 *cus = t;
167 return (0);
171 custr_alloc_buf(custr_t **cus, void *buf, size_t buflen)
173 int ret;
175 if (buflen == 0 || buf == NULL) {
176 errno = EINVAL;
177 return (-1);
180 if ((ret = custr_alloc(cus)) != 0)
181 return (ret);
183 (*cus)->cus_data = buf;
184 (*cus)->cus_datalen = buflen;
185 (*cus)->cus_strlen = 0;
186 (*cus)->cus_flags = CUSTR_FIXEDBUF;
187 (*cus)->cus_data[0] = '\0';
189 return (0);
192 void
193 custr_free(custr_t *cus)
195 if (cus == NULL)
196 return;
198 if ((cus->cus_flags & CUSTR_FIXEDBUF) == 0)
199 free(cus->cus_data);
200 free(cus);