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