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