xref: /titanic_52/usr/src/lib/libcustr/common/custr.c (revision 00e04c5de43d0960cd2a3ee9ebfbc6e0f2ab6946)
11f0c339eSJason King /*
21f0c339eSJason King  * This file and its contents are supplied under the terms of the
31f0c339eSJason King  * Common Development and Distribution License ("CDDL"), version 1.0.
41f0c339eSJason King  * You may only use this file in accordance with the terms of version
51f0c339eSJason King  * 1.0 of the CDDL.
61f0c339eSJason King  *
71f0c339eSJason King  * A full copy of the text of the CDDL should have accompanied this
81f0c339eSJason King  * source.  A copy of the CDDL is also available via the Internet at
91f0c339eSJason King  * http://www.illumos.org/license/CDDL.
101f0c339eSJason King  */
111f0c339eSJason King 
121f0c339eSJason King /*
131f0c339eSJason King  * String utility functions with dynamic memory management.
141f0c339eSJason King  */
151f0c339eSJason King 
161f0c339eSJason King /*
17*00e04c5dSJoshua M. Clulow  * Copyright 2019 Joyent, Inc.
181f0c339eSJason King  */
191f0c339eSJason King 
201f0c339eSJason King #include <stdlib.h>
211f0c339eSJason King #include <err.h>
221f0c339eSJason King #include <errno.h>
231f0c339eSJason King #include <string.h>
241f0c339eSJason King #include <stdio.h>
251f0c339eSJason King #include <stdarg.h>
261f0c339eSJason King #include <sys/debug.h>
271f0c339eSJason King 
281f0c339eSJason King #include "libcustr.h"
291f0c339eSJason King 
301f0c339eSJason King typedef enum {
311f0c339eSJason King 	CUSTR_FIXEDBUF	= 0x01
321f0c339eSJason King } custr_flags_t;
331f0c339eSJason King 
341f0c339eSJason King struct custr {
351f0c339eSJason King 	size_t cus_strlen;
361f0c339eSJason King 	size_t cus_datalen;
371f0c339eSJason King 	char *cus_data;
381f0c339eSJason King 	custr_flags_t cus_flags;
391f0c339eSJason King };
401f0c339eSJason King 
411f0c339eSJason King #define	STRING_CHUNK_SIZE	64
421f0c339eSJason King 
431f0c339eSJason King void
441f0c339eSJason King custr_reset(custr_t *cus)
451f0c339eSJason King {
461f0c339eSJason King 	if (cus->cus_data == NULL)
471f0c339eSJason King 		return;
481f0c339eSJason King 
491f0c339eSJason King 	cus->cus_strlen = 0;
501f0c339eSJason King 	cus->cus_data[0] = '\0';
511f0c339eSJason King }
521f0c339eSJason King 
531f0c339eSJason King size_t
541f0c339eSJason King custr_len(custr_t *cus)
551f0c339eSJason King {
561f0c339eSJason King 	return (cus->cus_strlen);
571f0c339eSJason King }
581f0c339eSJason King 
591f0c339eSJason King const char *
601f0c339eSJason King custr_cstr(custr_t *cus)
611f0c339eSJason King {
621f0c339eSJason King 	if (cus->cus_data == NULL) {
631f0c339eSJason King 		VERIFY(cus->cus_strlen == 0);
641f0c339eSJason King 		VERIFY(cus->cus_datalen == 0);
651f0c339eSJason King 
661f0c339eSJason King 		/*
671f0c339eSJason King 		 * This function should never return NULL.  If no buffer has
681f0c339eSJason King 		 * been allocated, return a pointer to a zero-length string.
691f0c339eSJason King 		 */
701f0c339eSJason King 		return ("");
711f0c339eSJason King 	}
721f0c339eSJason King 	return (cus->cus_data);
731f0c339eSJason King }
741f0c339eSJason King 
751f0c339eSJason King int
761f0c339eSJason King custr_append_vprintf(custr_t *cus, const char *fmt, va_list ap)
771f0c339eSJason King {
781f0c339eSJason King 	int len = vsnprintf(NULL, 0, fmt, ap);
791f0c339eSJason King 	size_t chunksz = STRING_CHUNK_SIZE;
801f0c339eSJason King 
81*00e04c5dSJoshua M. Clulow 	if (len < 0) {
821f0c339eSJason King 		return (len);
83*00e04c5dSJoshua M. Clulow 	}
841f0c339eSJason King 
851f0c339eSJason King 	while (chunksz < len) {
861f0c339eSJason King 		chunksz *= 2;
871f0c339eSJason King 	}
881f0c339eSJason King 
891f0c339eSJason King 	if (len + cus->cus_strlen + 1 >= cus->cus_datalen) {
901f0c339eSJason King 		char *new_data;
911f0c339eSJason King 		size_t new_datalen = cus->cus_datalen + chunksz;
921f0c339eSJason King 
931f0c339eSJason King 		if (cus->cus_flags & CUSTR_FIXEDBUF) {
941f0c339eSJason King 			errno = EOVERFLOW;
951f0c339eSJason King 			return (-1);
961f0c339eSJason King 		}
971f0c339eSJason King 
981f0c339eSJason King 		/*
991f0c339eSJason King 		 * Allocate replacement memory:
1001f0c339eSJason King 		 */
1011f0c339eSJason King 		if ((new_data = malloc(new_datalen)) == NULL) {
1021f0c339eSJason King 			return (-1);
1031f0c339eSJason King 		}
1041f0c339eSJason King 
1051f0c339eSJason King 		/*
1061f0c339eSJason King 		 * Copy existing data into replacement memory and free
1071f0c339eSJason King 		 * the old memory.
1081f0c339eSJason King 		 */
1091f0c339eSJason King 		if (cus->cus_data != NULL) {
1101f0c339eSJason King 			(void) memcpy(new_data, cus->cus_data,
1111f0c339eSJason King 			    cus->cus_strlen + 1);
1121f0c339eSJason King 			free(cus->cus_data);
1131f0c339eSJason King 		}
1141f0c339eSJason King 
1151f0c339eSJason King 		/*
1161f0c339eSJason King 		 * Swap in the replacement buffer:
1171f0c339eSJason King 		 */
1181f0c339eSJason King 		cus->cus_data = new_data;
1191f0c339eSJason King 		cus->cus_datalen = new_datalen;
1201f0c339eSJason King 	}
1211f0c339eSJason King 	/*
1221f0c339eSJason King 	 * Append new string to existing string:
1231f0c339eSJason King 	 */
124*00e04c5dSJoshua M. Clulow 	if ((len = vsnprintf(cus->cus_data + cus->cus_strlen,
125*00e04c5dSJoshua M. Clulow 	    cus->cus_datalen - cus->cus_strlen, fmt, ap)) < 0) {
1261f0c339eSJason King 		return (len);
127*00e04c5dSJoshua M. Clulow 	}
1281f0c339eSJason King 	cus->cus_strlen += len;
1291f0c339eSJason King 
1301f0c339eSJason King 	return (0);
1311f0c339eSJason King }
1321f0c339eSJason King 
1331f0c339eSJason King int
1341f0c339eSJason King custr_appendc(custr_t *cus, char newc)
1351f0c339eSJason King {
1361f0c339eSJason King 	return (custr_append_printf(cus, "%c", newc));
1371f0c339eSJason King }
1381f0c339eSJason King 
1391f0c339eSJason King int
1401f0c339eSJason King custr_append_printf(custr_t *cus, const char *fmt, ...)
1411f0c339eSJason King {
1421f0c339eSJason King 	va_list ap;
1431f0c339eSJason King 	int ret;
1441f0c339eSJason King 
1451f0c339eSJason King 	va_start(ap, fmt);
1461f0c339eSJason King 	ret = custr_append_vprintf(cus, fmt, ap);
1471f0c339eSJason King 	va_end(ap);
1481f0c339eSJason King 
1491f0c339eSJason King 	return (ret);
1501f0c339eSJason King }
1511f0c339eSJason King 
1521f0c339eSJason King int
1531f0c339eSJason King custr_append(custr_t *cus, const char *name)
1541f0c339eSJason King {
1551f0c339eSJason King 	return (custr_append_printf(cus, "%s", name));
1561f0c339eSJason King }
1571f0c339eSJason King 
1581f0c339eSJason King int
1591f0c339eSJason King custr_alloc(custr_t **cus)
1601f0c339eSJason King {
1611f0c339eSJason King 	custr_t *t;
1621f0c339eSJason King 
1631f0c339eSJason King 	if ((t = calloc(1, sizeof (*t))) == NULL) {
1641f0c339eSJason King 		*cus = NULL;
1651f0c339eSJason King 		return (-1);
1661f0c339eSJason King 	}
1671f0c339eSJason King 
1681f0c339eSJason King 	*cus = t;
1691f0c339eSJason King 	return (0);
1701f0c339eSJason King }
1711f0c339eSJason King 
1721f0c339eSJason King int
1731f0c339eSJason King custr_alloc_buf(custr_t **cus, void *buf, size_t buflen)
1741f0c339eSJason King {
1751f0c339eSJason King 	int ret;
1761f0c339eSJason King 
1771f0c339eSJason King 	if (buflen == 0 || buf == NULL) {
1781f0c339eSJason King 		errno = EINVAL;
1791f0c339eSJason King 		return (-1);
1801f0c339eSJason King 	}
1811f0c339eSJason King 
1821f0c339eSJason King 	if ((ret = custr_alloc(cus)) != 0)
1831f0c339eSJason King 		return (ret);
1841f0c339eSJason King 
1851f0c339eSJason King 	(*cus)->cus_data = buf;
1861f0c339eSJason King 	(*cus)->cus_datalen = buflen;
1871f0c339eSJason King 	(*cus)->cus_strlen = 0;
1881f0c339eSJason King 	(*cus)->cus_flags = CUSTR_FIXEDBUF;
1891f0c339eSJason King 	(*cus)->cus_data[0] = '\0';
1901f0c339eSJason King 
1911f0c339eSJason King 	return (0);
1921f0c339eSJason King }
1931f0c339eSJason King 
1941f0c339eSJason King void
1951f0c339eSJason King custr_free(custr_t *cus)
1961f0c339eSJason King {
1971f0c339eSJason King 	if (cus == NULL)
1981f0c339eSJason King 		return;
1991f0c339eSJason King 
2001f0c339eSJason King 	if ((cus->cus_flags & CUSTR_FIXEDBUF) == 0)
2011f0c339eSJason King 		free(cus->cus_data);
2021f0c339eSJason King 	free(cus);
2031f0c339eSJason King }
204