1 /* ----------------------------------------------------------------------- * 2 * 3 * Copyright 2008 H. Peter Anvin - All Rights Reserved 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, 8 * Boston MA 02110-1301, USA; either version 2 of the License, or 9 * (at your option) any later version; incorporated herein by reference. 10 * 11 * ----------------------------------------------------------------------- */ 12 13 /* 14 * refstr.c 15 * 16 * Simple reference-counted strings 17 */ 18 19 #include <stdlib.h> 20 #include <string.h> 21 #include <stdio.h> 22 #include "refstr.h" 23 24 /* Allocate space for a refstring of len bytes, plus final null */ 25 /* The final null is inserted in the string; the rest is uninitialized. */ 26 char *refstr_alloc(size_t len) 27 { 28 char *r = malloc(sizeof(unsigned int) + len + 1); 29 if (!r) 30 return NULL; 31 *(unsigned int *)r = 1; 32 r += sizeof(unsigned int); 33 r[len] = '\0'; 34 return r; 35 } 36 37 const char *refstrndup(const char *str, size_t len) 38 { 39 char *r; 40 41 if (!str) 42 return NULL; 43 44 len = strnlen(str, len); 45 r = refstr_alloc(len); 46 if (r) 47 memcpy(r, str, len); 48 return r; 49 } 50 51 const char *refstrdup(const char *str) 52 { 53 char *r; 54 size_t len; 55 56 if (!str) 57 return NULL; 58 59 len = strlen(str); 60 r = refstr_alloc(len); 61 if (r) 62 memcpy(r, str, len); 63 return r; 64 } 65 66 int vrsprintf(const char **bufp, const char *fmt, va_list ap) 67 { 68 va_list ap1; 69 int len; 70 char *p; 71 72 va_copy(ap1, ap); 73 len = vsnprintf(NULL, 0, fmt, ap1); 74 va_end(ap1); 75 76 *bufp = p = refstr_alloc(len); 77 if (!p) 78 return -1; 79 80 return vsnprintf(p, len + 1, fmt, ap); 81 } 82 83 int rsprintf(const char **bufp, const char *fmt, ...) 84 { 85 int rv; 86 va_list ap; 87 88 va_start(ap, fmt); 89 rv = vrsprintf(bufp, fmt, ap); 90 va_end(ap); 91 92 return rv; 93 } 94 95 void refstr_put(const char *r) 96 { 97 unsigned int *ref; 98 99 if (r) { 100 ref = (unsigned int *)r - 1; 101 102 if (!--*ref) 103 free(ref); 104 } 105 } 106