1 /* $NetBSD: mstring.c,v 1.7 2024/09/14 21:29:02 christos Exp $ */ 2 3 /* Id: mstring.c,v 1.10 2023/02/26 10:15:01 tom Exp */ 4 #if HAVE_NBTOOL_CONFIG_H 5 #include "nbtool_config.h" 6 #endif 7 8 #include <sys/cdefs.h> 9 __RCSID("$NetBSD: mstring.c,v 1.7 2024/09/14 21:29:02 christos Exp $"); 10 11 #include <stdlib.h> 12 #include <stdio.h> 13 #include <stdarg.h> 14 #include <ctype.h> 15 #include <string.h> 16 #include "defs.h" 17 18 /* parameters about string length. HEAD is the starting size and 19 ** HEAD+TAIL should be a power of two */ 20 #define HEAD 24 21 #define TAIL 8 22 23 static char *buf_ptr; 24 static size_t buf_len; 25 26 void 27 msprintf(struct mstring *s, const char *fmt, ...) 28 { 29 va_list args; 30 size_t len; 31 #ifdef HAVE_VSNPRINTF 32 int changed; 33 #endif 34 35 if (!s || !s->base) 36 return; 37 38 if (buf_len == 0) 39 { 40 buf_ptr = malloc(buf_len = 4096); 41 } 42 if (buf_ptr == 0) 43 { 44 return; 45 } 46 47 #ifdef HAVE_VSNPRINTF 48 do 49 { 50 va_start(args, fmt); 51 len = (size_t)vsnprintf(buf_ptr, buf_len, fmt, args); 52 va_end(args); 53 if ((changed = (len > buf_len)) != 0) 54 { 55 char *new_ptr = realloc(buf_ptr, (buf_len * 3) / 2); 56 if (new_ptr == 0) 57 { 58 free(buf_ptr); 59 buf_ptr = 0; 60 return; 61 } 62 buf_ptr = new_ptr; 63 } 64 } 65 while (changed); 66 #else 67 va_start(args, fmt); 68 len = (size_t)vsprintf(buf_ptr, fmt, args); 69 va_end(args); 70 if (len >= buf_len) 71 return; 72 #endif 73 74 if (len > (size_t)(s->end - s->ptr)) 75 { 76 char *new_base; 77 size_t cp = (size_t)(s->ptr - s->base); 78 size_t cl = (size_t)(s->end - s->base); 79 size_t nl = cl; 80 while (len > (nl - cp)) 81 nl = nl + nl + TAIL; 82 if ((new_base = realloc(s->base, nl))) 83 { 84 s->base = new_base; 85 s->ptr = s->base + cp; 86 s->end = s->base + nl; 87 } 88 else 89 { 90 free(s->base); 91 s->base = 0; 92 s->ptr = 0; 93 s->end = 0; 94 return; 95 } 96 } 97 memcpy(s->ptr, buf_ptr, len); 98 s->ptr += len; 99 } 100 101 int 102 mputchar(struct mstring *s, int ch) 103 { 104 if (!s || !s->base) 105 return ch; 106 if (s->ptr == s->end) 107 { 108 size_t len = (size_t)(s->end - s->base); 109 if ((s->base = realloc(s->base, len + len + TAIL))) 110 { 111 s->ptr = s->base + len; 112 s->end = s->base + len + len + TAIL; 113 } 114 else 115 { 116 s->ptr = s->end = 0; 117 return ch; 118 } 119 } 120 *s->ptr++ = (char)ch; 121 return ch; 122 } 123 124 struct mstring * 125 msnew(void) 126 { 127 struct mstring *n = TMALLOC(struct mstring, 1); 128 129 if (n) 130 { 131 if ((n->base = n->ptr = MALLOC(HEAD)) != 0) 132 { 133 n->end = n->base + HEAD; 134 } 135 else 136 { 137 free(n); 138 n = 0; 139 } 140 } 141 return n; 142 } 143 144 struct mstring * 145 msrenew(char *value) 146 { 147 struct mstring *r = 0; 148 if (value != 0) 149 { 150 r = msnew(); 151 r->base = value; 152 r->end = value + strlen(value); 153 r->ptr = r->end; 154 } 155 return r; 156 } 157 158 char * 159 msdone(struct mstring *s) 160 { 161 char *r = 0; 162 if (s) 163 { 164 mputc(s, 0); 165 r = s->base; 166 free(s); 167 } 168 return r; 169 } 170 171 #if defined(YYBTYACC) 172 /* compare two strings, ignoring whitespace, except between two letters or 173 ** digits (and treat all of these as equal) */ 174 int 175 strnscmp(const char *a, const char *b) 176 { 177 while (1) 178 { 179 while (isspace(UCH(*a))) 180 a++; 181 while (isspace(UCH(*b))) 182 b++; 183 while (*a && *a == *b) 184 a++, b++; 185 if (isspace(UCH(*a))) 186 { 187 if (isalnum(UCH(a[-1])) && isalnum(UCH(*b))) 188 break; 189 } 190 else if (isspace(UCH(*b))) 191 { 192 if (isalnum(UCH(b[-1])) && isalnum(UCH(*a))) 193 break; 194 } 195 else 196 break; 197 } 198 return *a - *b; 199 } 200 201 unsigned int 202 strnshash(const char *s) 203 { 204 unsigned int h = 0; 205 206 while (*s) 207 { 208 if (!isspace(UCH(*s))) 209 h = (h << 5) - h + (unsigned char)*s; 210 s++; 211 } 212 return h; 213 } 214 #endif 215 216 #ifdef NO_LEAKS 217 void 218 mstring_leaks(void) 219 { 220 free(buf_ptr); 221 buf_ptr = 0; 222 buf_len = 0; 223 } 224 #endif 225