1 /* $Id: mstring.c,v 1.10 2023/02/26 10:15:01 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
msprintf(struct mstring * s,const char * fmt,...)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
mputchar(struct mstring * s,int ch)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 *
msnew(void)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 *
msrenew(char * value)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 *
msdone(struct mstring * s)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
strnscmp(const char * a,const char * b)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
strnshash(const char * s)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
mstring_leaks(void)210 mstring_leaks(void)
211 {
212 free(buf_ptr);
213 buf_ptr = 0;
214 buf_len = 0;
215 }
216 #endif
217