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