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
msprintf(struct mstring * s,const char * fmt,...)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
mputchar(struct mstring * s,int ch)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 *
msnew(void)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 *
msrenew(char * value)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 *
msdone(struct mstring * s)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
strnscmp(const char * a,const char * b)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
strnshash(const char * s)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
mstring_leaks(void)218 mstring_leaks(void)
219 {
220 free(buf_ptr);
221 buf_ptr = 0;
222 buf_len = 0;
223 }
224 #endif
225