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
17static char *buf_ptr;
18static size_t buf_len;
19
20void
21msprintf(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
96int
97mputchar(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
119struct mstring *
120msnew(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
139char *
140msdone(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) */
155int
156strnscmp(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
182unsigned int
183strnshash(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
198void
199mstring_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