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 <sys/module.h> 23 #include "refstr.h" 24 25 /* Allocate space for a refstring of len bytes, plus final null */ 26 /* The final null is inserted in the string; the rest is uninitialized. */ 27 char *refstr_alloc(size_t len) 28 { 29 char *r = malloc(sizeof(unsigned int) + len + 1); 30 if (!r) 31 return NULL; 32 *(unsigned int *)r = 1; 33 r += sizeof(unsigned int); 34 r[len] = '\0'; 35 return r; 36 } 37 38 const char *refstrndup(const char *str, size_t len) 39 { 40 char *r; 41 42 if (!str) 43 return NULL; 44 45 len = strnlen(str, len); 46 r = refstr_alloc(len); 47 if (r) 48 memcpy(r, str, len); 49 return r; 50 } 51 52 const char *refstrdup(const char *str) 53 { 54 char *r; 55 size_t len; 56 57 if (!str) 58 return NULL; 59 60 len = strlen(str); 61 r = refstr_alloc(len); 62 if (r) 63 memcpy(r, str, len); 64 return r; 65 } 66 67 int vrsprintf(const char **bufp, const char *fmt, va_list ap) 68 { 69 va_list ap1; 70 int len; 71 char *p; 72 73 va_copy(ap1, ap); 74 len = vsnprintf(NULL, 0, fmt, ap1); 75 va_end(ap1); 76 77 *bufp = p = refstr_alloc(len); 78 if (!p) 79 return -1; 80 81 return vsnprintf(p, len + 1, fmt, ap); 82 } 83 84 int rsprintf(const char **bufp, const char *fmt, ...) 85 { 86 int rv; 87 va_list ap; 88 89 va_start(ap, fmt); 90 rv = vrsprintf(bufp, fmt, ap); 91 va_end(ap); 92 93 return rv; 94 } 95 96 void refstr_put(const char *r) 97 { 98 unsigned int *ref; 99 100 if (r) { 101 ref = (unsigned int *)r - 1; 102 103 if (!--*ref) 104 free(ref); 105 } 106 } 107