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