xref: /netbsd-src/external/bsd/byacc/dist/mstring.c (revision 3d8f5b8dd9f188f856affd984b68f2960ff20d65)
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