xref: /freebsd/contrib/byacc/mstring.c (revision 12e0d316644a4f80f5f1f78cf07bd93def43b1ca)
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
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