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