1196c7f05SJoshua M. Clulow /* 2196c7f05SJoshua M. Clulow * This file and its contents are supplied under the terms of the 3196c7f05SJoshua M. Clulow * Common Development and Distribution License ("CDDL"), version 1.0. 4196c7f05SJoshua M. Clulow * You may only use this file in accordance with the terms of version 5196c7f05SJoshua M. Clulow * 1.0 of the CDDL. 6196c7f05SJoshua M. Clulow * 7196c7f05SJoshua M. Clulow * A full copy of the text of the CDDL should have accompanied this 8196c7f05SJoshua M. Clulow * source. A copy of the CDDL is also available via the Internet at 9196c7f05SJoshua M. Clulow * http://www.illumos.org/license/CDDL. 10196c7f05SJoshua M. Clulow */ 11196c7f05SJoshua M. Clulow 12196c7f05SJoshua M. Clulow /* 13196c7f05SJoshua M. Clulow * String utility functions with dynamic memory management. 14196c7f05SJoshua M. Clulow */ 15196c7f05SJoshua M. Clulow 16196c7f05SJoshua M. Clulow /* 17*500cf85bSJason King * Copyright 2018 Joyent, Inc. 18196c7f05SJoshua M. Clulow */ 19196c7f05SJoshua M. Clulow 20196c7f05SJoshua M. Clulow #include <stdlib.h> 21196c7f05SJoshua M. Clulow #include <err.h> 22*500cf85bSJason King #include <errno.h> 23196c7f05SJoshua M. Clulow #include <string.h> 24fc2512cfSRobert Mustacchi #include <stdio.h> 25fc2512cfSRobert Mustacchi #include <stdarg.h> 26fc2512cfSRobert Mustacchi #include <sys/debug.h> 27196c7f05SJoshua M. Clulow 28*500cf85bSJason King #include "libcustr.h" 29196c7f05SJoshua M. Clulow 30fc2512cfSRobert Mustacchi typedef enum { 31fc2512cfSRobert Mustacchi CUSTR_FIXEDBUF = 0x01 32fc2512cfSRobert Mustacchi } custr_flags_t; 33fc2512cfSRobert Mustacchi 34196c7f05SJoshua M. Clulow struct custr { 35196c7f05SJoshua M. Clulow size_t cus_strlen; 36196c7f05SJoshua M. Clulow size_t cus_datalen; 37196c7f05SJoshua M. Clulow char *cus_data; 38fc2512cfSRobert Mustacchi custr_flags_t cus_flags; 39196c7f05SJoshua M. Clulow }; 40196c7f05SJoshua M. Clulow 41196c7f05SJoshua M. Clulow #define STRING_CHUNK_SIZE 64 42196c7f05SJoshua M. Clulow 43196c7f05SJoshua M. Clulow void 44196c7f05SJoshua M. Clulow custr_reset(custr_t *cus) 45196c7f05SJoshua M. Clulow { 46196c7f05SJoshua M. Clulow if (cus->cus_data == NULL) 47196c7f05SJoshua M. Clulow return; 48196c7f05SJoshua M. Clulow 49196c7f05SJoshua M. Clulow cus->cus_strlen = 0; 50196c7f05SJoshua M. Clulow cus->cus_data[0] = '\0'; 51196c7f05SJoshua M. Clulow } 52196c7f05SJoshua M. Clulow 53196c7f05SJoshua M. Clulow size_t 54196c7f05SJoshua M. Clulow custr_len(custr_t *cus) 55196c7f05SJoshua M. Clulow { 56196c7f05SJoshua M. Clulow return (cus->cus_strlen); 57196c7f05SJoshua M. Clulow } 58196c7f05SJoshua M. Clulow 59196c7f05SJoshua M. Clulow const char * 60196c7f05SJoshua M. Clulow custr_cstr(custr_t *cus) 61196c7f05SJoshua M. Clulow { 62fc2512cfSRobert Mustacchi if (cus->cus_data == NULL) { 63fc2512cfSRobert Mustacchi VERIFY(cus->cus_strlen == 0); 64fc2512cfSRobert Mustacchi VERIFY(cus->cus_datalen == 0); 65196c7f05SJoshua M. Clulow 66fc2512cfSRobert Mustacchi /* 67fc2512cfSRobert Mustacchi * This function should never return NULL. If no buffer has 68fc2512cfSRobert Mustacchi * been allocated, return a pointer to a zero-length string. 69fc2512cfSRobert Mustacchi */ 70fc2512cfSRobert Mustacchi return (""); 71fc2512cfSRobert Mustacchi } 72fc2512cfSRobert Mustacchi return (cus->cus_data); 73196c7f05SJoshua M. Clulow } 74196c7f05SJoshua M. Clulow 75196c7f05SJoshua M. Clulow int 76fc2512cfSRobert Mustacchi custr_append_vprintf(custr_t *cus, const char *fmt, va_list ap) 77196c7f05SJoshua M. Clulow { 78fc2512cfSRobert Mustacchi int len = vsnprintf(NULL, 0, fmt, ap); 79196c7f05SJoshua M. Clulow size_t chunksz = STRING_CHUNK_SIZE; 80196c7f05SJoshua M. Clulow 81fc2512cfSRobert Mustacchi if (len == -1) 82fc2512cfSRobert Mustacchi return (len); 83fc2512cfSRobert Mustacchi 84196c7f05SJoshua M. Clulow while (chunksz < len) { 85196c7f05SJoshua M. Clulow chunksz *= 2; 86196c7f05SJoshua M. Clulow } 87196c7f05SJoshua M. Clulow 88196c7f05SJoshua M. Clulow if (len + cus->cus_strlen + 1 >= cus->cus_datalen) { 89196c7f05SJoshua M. Clulow char *new_data; 90196c7f05SJoshua M. Clulow size_t new_datalen = cus->cus_datalen + chunksz; 91196c7f05SJoshua M. Clulow 92fc2512cfSRobert Mustacchi if (cus->cus_flags & CUSTR_FIXEDBUF) { 93fc2512cfSRobert Mustacchi errno = EOVERFLOW; 94fc2512cfSRobert Mustacchi return (-1); 95fc2512cfSRobert Mustacchi } 96fc2512cfSRobert Mustacchi 97196c7f05SJoshua M. Clulow /* 98196c7f05SJoshua M. Clulow * Allocate replacement memory: 99196c7f05SJoshua M. Clulow */ 100196c7f05SJoshua M. Clulow if ((new_data = malloc(new_datalen)) == NULL) { 101196c7f05SJoshua M. Clulow return (-1); 102196c7f05SJoshua M. Clulow } 103196c7f05SJoshua M. Clulow 104196c7f05SJoshua M. Clulow /* 105196c7f05SJoshua M. Clulow * Copy existing data into replacement memory and free 106196c7f05SJoshua M. Clulow * the old memory. 107196c7f05SJoshua M. Clulow */ 108196c7f05SJoshua M. Clulow if (cus->cus_data != NULL) { 109196c7f05SJoshua M. Clulow (void) memcpy(new_data, cus->cus_data, 110196c7f05SJoshua M. Clulow cus->cus_strlen + 1); 111196c7f05SJoshua M. Clulow free(cus->cus_data); 112196c7f05SJoshua M. Clulow } 113196c7f05SJoshua M. Clulow 114196c7f05SJoshua M. Clulow /* 115196c7f05SJoshua M. Clulow * Swap in the replacement buffer: 116196c7f05SJoshua M. Clulow */ 117196c7f05SJoshua M. Clulow cus->cus_data = new_data; 118196c7f05SJoshua M. Clulow cus->cus_datalen = new_datalen; 119196c7f05SJoshua M. Clulow } 120196c7f05SJoshua M. Clulow /* 121196c7f05SJoshua M. Clulow * Append new string to existing string: 122196c7f05SJoshua M. Clulow */ 123fc2512cfSRobert Mustacchi len = vsnprintf(cus->cus_data + cus->cus_strlen, 124fc2512cfSRobert Mustacchi (uintptr_t)cus->cus_data - (uintptr_t)cus->cus_strlen, fmt, ap); 125fc2512cfSRobert Mustacchi if (len == -1) 126fc2512cfSRobert Mustacchi return (len); 127196c7f05SJoshua M. Clulow cus->cus_strlen += len; 128196c7f05SJoshua M. Clulow 129196c7f05SJoshua M. Clulow return (0); 130196c7f05SJoshua M. Clulow } 131196c7f05SJoshua M. Clulow 132fc2512cfSRobert Mustacchi int 133fc2512cfSRobert Mustacchi custr_appendc(custr_t *cus, char newc) 134fc2512cfSRobert Mustacchi { 135fc2512cfSRobert Mustacchi return (custr_append_printf(cus, "%c", newc)); 136fc2512cfSRobert Mustacchi } 137fc2512cfSRobert Mustacchi 138fc2512cfSRobert Mustacchi int 139fc2512cfSRobert Mustacchi custr_append_printf(custr_t *cus, const char *fmt, ...) 140fc2512cfSRobert Mustacchi { 141fc2512cfSRobert Mustacchi va_list ap; 142fc2512cfSRobert Mustacchi int ret; 143fc2512cfSRobert Mustacchi 144fc2512cfSRobert Mustacchi va_start(ap, fmt); 145fc2512cfSRobert Mustacchi ret = custr_append_vprintf(cus, fmt, ap); 146fc2512cfSRobert Mustacchi va_end(ap); 147fc2512cfSRobert Mustacchi 148fc2512cfSRobert Mustacchi return (ret); 149fc2512cfSRobert Mustacchi } 150fc2512cfSRobert Mustacchi 151fc2512cfSRobert Mustacchi int 152fc2512cfSRobert Mustacchi custr_append(custr_t *cus, const char *name) 153fc2512cfSRobert Mustacchi { 154fc2512cfSRobert Mustacchi return (custr_append_printf(cus, "%s", name)); 155fc2512cfSRobert Mustacchi } 156fc2512cfSRobert Mustacchi 157196c7f05SJoshua M. Clulow int 158196c7f05SJoshua M. Clulow custr_alloc(custr_t **cus) 159196c7f05SJoshua M. Clulow { 160196c7f05SJoshua M. Clulow custr_t *t; 161196c7f05SJoshua M. Clulow 162196c7f05SJoshua M. Clulow if ((t = calloc(1, sizeof (*t))) == NULL) { 163196c7f05SJoshua M. Clulow *cus = NULL; 164196c7f05SJoshua M. Clulow return (-1); 165196c7f05SJoshua M. Clulow } 166196c7f05SJoshua M. Clulow 167196c7f05SJoshua M. Clulow *cus = t; 168196c7f05SJoshua M. Clulow return (0); 169196c7f05SJoshua M. Clulow } 170196c7f05SJoshua M. Clulow 171fc2512cfSRobert Mustacchi int 172fc2512cfSRobert Mustacchi custr_alloc_buf(custr_t **cus, void *buf, size_t buflen) 173fc2512cfSRobert Mustacchi { 174fc2512cfSRobert Mustacchi int ret; 175fc2512cfSRobert Mustacchi 176fc2512cfSRobert Mustacchi if (buflen == 0 || buf == NULL) { 177fc2512cfSRobert Mustacchi errno = EINVAL; 178fc2512cfSRobert Mustacchi return (-1); 179fc2512cfSRobert Mustacchi } 180fc2512cfSRobert Mustacchi 181fc2512cfSRobert Mustacchi if ((ret = custr_alloc(cus)) != 0) 182fc2512cfSRobert Mustacchi return (ret); 183fc2512cfSRobert Mustacchi 184fc2512cfSRobert Mustacchi (*cus)->cus_data = buf; 185fc2512cfSRobert Mustacchi (*cus)->cus_datalen = buflen; 186fc2512cfSRobert Mustacchi (*cus)->cus_strlen = 0; 187fc2512cfSRobert Mustacchi (*cus)->cus_flags = CUSTR_FIXEDBUF; 188fc2512cfSRobert Mustacchi (*cus)->cus_data[0] = '\0'; 189fc2512cfSRobert Mustacchi 190fc2512cfSRobert Mustacchi return (0); 191fc2512cfSRobert Mustacchi } 192fc2512cfSRobert Mustacchi 193196c7f05SJoshua M. Clulow void 194196c7f05SJoshua M. Clulow custr_free(custr_t *cus) 195196c7f05SJoshua M. Clulow { 196196c7f05SJoshua M. Clulow if (cus == NULL) 197196c7f05SJoshua M. Clulow return; 198196c7f05SJoshua M. Clulow 199fc2512cfSRobert Mustacchi if ((cus->cus_flags & CUSTR_FIXEDBUF) == 0) 200fc2512cfSRobert Mustacchi free(cus->cus_data); 201196c7f05SJoshua M. Clulow free(cus); 202196c7f05SJoshua M. Clulow } 203