1e01ec5d5SJason King /*
2e01ec5d5SJason King * This file and its contents are supplied under the terms of the
3e01ec5d5SJason King * Common Development and Distribution License ("CDDL"), version 1.0.
4e01ec5d5SJason King * You may only use this file in accordance with the terms of version
5e01ec5d5SJason King * 1.0 of the CDDL.
6e01ec5d5SJason King *
7e01ec5d5SJason King * A full copy of the text of the CDDL should have accompanied this
8e01ec5d5SJason King * source. A copy of the CDDL is also available via the Internet at
9e01ec5d5SJason King * http://www.illumos.org/license/CDDL.
10e01ec5d5SJason King */
11e01ec5d5SJason King
12e01ec5d5SJason King /*
13e01ec5d5SJason King * String utility functions with dynamic memory management.
14e01ec5d5SJason King */
15e01ec5d5SJason King
16e01ec5d5SJason King /*
17*0c4954e0SJoshua M. Clulow * Copyright 2019 Joyent, Inc.
18e01ec5d5SJason King */
19e01ec5d5SJason King
20e01ec5d5SJason King #include <stdlib.h>
21e01ec5d5SJason King #include <err.h>
22e01ec5d5SJason King #include <errno.h>
23e01ec5d5SJason King #include <string.h>
24e01ec5d5SJason King #include <stdio.h>
25e01ec5d5SJason King #include <stdarg.h>
26e01ec5d5SJason King #include <sys/debug.h>
27e01ec5d5SJason King
28e01ec5d5SJason King #include "libcustr.h"
29e01ec5d5SJason King
30e01ec5d5SJason King typedef enum {
31e01ec5d5SJason King CUSTR_FIXEDBUF = 0x01
32e01ec5d5SJason King } custr_flags_t;
33e01ec5d5SJason King
34e01ec5d5SJason King struct custr {
35e01ec5d5SJason King size_t cus_strlen;
36e01ec5d5SJason King size_t cus_datalen;
37e01ec5d5SJason King char *cus_data;
38e01ec5d5SJason King custr_flags_t cus_flags;
39e01ec5d5SJason King };
40e01ec5d5SJason King
41e01ec5d5SJason King #define STRING_CHUNK_SIZE 64
42e01ec5d5SJason King
43e01ec5d5SJason King void
custr_reset(custr_t * cus)44e01ec5d5SJason King custr_reset(custr_t *cus)
45e01ec5d5SJason King {
46e01ec5d5SJason King if (cus->cus_data == NULL)
47e01ec5d5SJason King return;
48e01ec5d5SJason King
49e01ec5d5SJason King cus->cus_strlen = 0;
50e01ec5d5SJason King cus->cus_data[0] = '\0';
51e01ec5d5SJason King }
52e01ec5d5SJason King
53e01ec5d5SJason King size_t
custr_len(custr_t * cus)54e01ec5d5SJason King custr_len(custr_t *cus)
55e01ec5d5SJason King {
56e01ec5d5SJason King return (cus->cus_strlen);
57e01ec5d5SJason King }
58e01ec5d5SJason King
59e01ec5d5SJason King const char *
custr_cstr(custr_t * cus)60e01ec5d5SJason King custr_cstr(custr_t *cus)
61e01ec5d5SJason King {
62e01ec5d5SJason King if (cus->cus_data == NULL) {
63e01ec5d5SJason King VERIFY(cus->cus_strlen == 0);
64e01ec5d5SJason King VERIFY(cus->cus_datalen == 0);
65e01ec5d5SJason King
66e01ec5d5SJason King /*
67e01ec5d5SJason King * This function should never return NULL. If no buffer has
68e01ec5d5SJason King * been allocated, return a pointer to a zero-length string.
69e01ec5d5SJason King */
70e01ec5d5SJason King return ("");
71e01ec5d5SJason King }
72e01ec5d5SJason King return (cus->cus_data);
73e01ec5d5SJason King }
74e01ec5d5SJason King
75e01ec5d5SJason King int
custr_append_vprintf(custr_t * cus,const char * fmt,va_list ap)76e01ec5d5SJason King custr_append_vprintf(custr_t *cus, const char *fmt, va_list ap)
77e01ec5d5SJason King {
78e01ec5d5SJason King int len = vsnprintf(NULL, 0, fmt, ap);
79e01ec5d5SJason King size_t chunksz = STRING_CHUNK_SIZE;
80e01ec5d5SJason King
81*0c4954e0SJoshua M. Clulow if (len < 0) {
82e01ec5d5SJason King return (len);
83*0c4954e0SJoshua M. Clulow }
84e01ec5d5SJason King
85e01ec5d5SJason King while (chunksz < len) {
86e01ec5d5SJason King chunksz *= 2;
87e01ec5d5SJason King }
88e01ec5d5SJason King
89e01ec5d5SJason King if (len + cus->cus_strlen + 1 >= cus->cus_datalen) {
90e01ec5d5SJason King char *new_data;
91e01ec5d5SJason King size_t new_datalen = cus->cus_datalen + chunksz;
92e01ec5d5SJason King
93e01ec5d5SJason King if (cus->cus_flags & CUSTR_FIXEDBUF) {
94e01ec5d5SJason King errno = EOVERFLOW;
95e01ec5d5SJason King return (-1);
96e01ec5d5SJason King }
97e01ec5d5SJason King
98e01ec5d5SJason King /*
99e01ec5d5SJason King * Allocate replacement memory:
100e01ec5d5SJason King */
101e01ec5d5SJason King if ((new_data = malloc(new_datalen)) == NULL) {
102e01ec5d5SJason King return (-1);
103e01ec5d5SJason King }
104e01ec5d5SJason King
105e01ec5d5SJason King /*
106e01ec5d5SJason King * Copy existing data into replacement memory and free
107e01ec5d5SJason King * the old memory.
108e01ec5d5SJason King */
109e01ec5d5SJason King if (cus->cus_data != NULL) {
110e01ec5d5SJason King (void) memcpy(new_data, cus->cus_data,
111e01ec5d5SJason King cus->cus_strlen + 1);
112e01ec5d5SJason King free(cus->cus_data);
113e01ec5d5SJason King }
114e01ec5d5SJason King
115e01ec5d5SJason King /*
116e01ec5d5SJason King * Swap in the replacement buffer:
117e01ec5d5SJason King */
118e01ec5d5SJason King cus->cus_data = new_data;
119e01ec5d5SJason King cus->cus_datalen = new_datalen;
120e01ec5d5SJason King }
121e01ec5d5SJason King /*
122e01ec5d5SJason King * Append new string to existing string:
123e01ec5d5SJason King */
124*0c4954e0SJoshua M. Clulow if ((len = vsnprintf(cus->cus_data + cus->cus_strlen,
125*0c4954e0SJoshua M. Clulow cus->cus_datalen - cus->cus_strlen, fmt, ap)) < 0) {
126e01ec5d5SJason King return (len);
127*0c4954e0SJoshua M. Clulow }
128e01ec5d5SJason King cus->cus_strlen += len;
129e01ec5d5SJason King
130e01ec5d5SJason King return (0);
131e01ec5d5SJason King }
132e01ec5d5SJason King
133e01ec5d5SJason King int
custr_appendc(custr_t * cus,char newc)134e01ec5d5SJason King custr_appendc(custr_t *cus, char newc)
135e01ec5d5SJason King {
136e01ec5d5SJason King return (custr_append_printf(cus, "%c", newc));
137e01ec5d5SJason King }
138e01ec5d5SJason King
139e01ec5d5SJason King int
custr_append_printf(custr_t * cus,const char * fmt,...)140e01ec5d5SJason King custr_append_printf(custr_t *cus, const char *fmt, ...)
141e01ec5d5SJason King {
142e01ec5d5SJason King va_list ap;
143e01ec5d5SJason King int ret;
144e01ec5d5SJason King
145e01ec5d5SJason King va_start(ap, fmt);
146e01ec5d5SJason King ret = custr_append_vprintf(cus, fmt, ap);
147e01ec5d5SJason King va_end(ap);
148e01ec5d5SJason King
149e01ec5d5SJason King return (ret);
150e01ec5d5SJason King }
151e01ec5d5SJason King
152e01ec5d5SJason King int
custr_append(custr_t * cus,const char * name)153e01ec5d5SJason King custr_append(custr_t *cus, const char *name)
154e01ec5d5SJason King {
155e01ec5d5SJason King return (custr_append_printf(cus, "%s", name));
156e01ec5d5SJason King }
157e01ec5d5SJason King
158e01ec5d5SJason King int
custr_alloc(custr_t ** cus)159e01ec5d5SJason King custr_alloc(custr_t **cus)
160e01ec5d5SJason King {
161e01ec5d5SJason King custr_t *t;
162e01ec5d5SJason King
163e01ec5d5SJason King if ((t = calloc(1, sizeof (*t))) == NULL) {
164e01ec5d5SJason King *cus = NULL;
165e01ec5d5SJason King return (-1);
166e01ec5d5SJason King }
167e01ec5d5SJason King
168e01ec5d5SJason King *cus = t;
169e01ec5d5SJason King return (0);
170e01ec5d5SJason King }
171e01ec5d5SJason King
172e01ec5d5SJason King int
custr_alloc_buf(custr_t ** cus,void * buf,size_t buflen)173e01ec5d5SJason King custr_alloc_buf(custr_t **cus, void *buf, size_t buflen)
174e01ec5d5SJason King {
175e01ec5d5SJason King int ret;
176e01ec5d5SJason King
177e01ec5d5SJason King if (buflen == 0 || buf == NULL) {
178e01ec5d5SJason King errno = EINVAL;
179e01ec5d5SJason King return (-1);
180e01ec5d5SJason King }
181e01ec5d5SJason King
182e01ec5d5SJason King if ((ret = custr_alloc(cus)) != 0)
183e01ec5d5SJason King return (ret);
184e01ec5d5SJason King
185e01ec5d5SJason King (*cus)->cus_data = buf;
186e01ec5d5SJason King (*cus)->cus_datalen = buflen;
187e01ec5d5SJason King (*cus)->cus_strlen = 0;
188e01ec5d5SJason King (*cus)->cus_flags = CUSTR_FIXEDBUF;
189e01ec5d5SJason King (*cus)->cus_data[0] = '\0';
190e01ec5d5SJason King
191e01ec5d5SJason King return (0);
192e01ec5d5SJason King }
193e01ec5d5SJason King
194e01ec5d5SJason King void
custr_free(custr_t * cus)195e01ec5d5SJason King custr_free(custr_t *cus)
196e01ec5d5SJason King {
197e01ec5d5SJason King if (cus == NULL)
198e01ec5d5SJason King return;
199e01ec5d5SJason King
200e01ec5d5SJason King if ((cus->cus_flags & CUSTR_FIXEDBUF) == 0)
201e01ec5d5SJason King free(cus->cus_data);
202e01ec5d5SJason King free(cus);
203e01ec5d5SJason King }
204