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