xref: /dragonfly/contrib/byacc/mstring.c (revision faa6539e3eb14adda687112eba35d0f6a2eefa13)
1 /* $Id: mstring.c,v 1.9 2019/11/19 23:54:53 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
msprintf(struct mstring * s,const char * fmt,...)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
mputchar(struct mstring * s,int ch)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 *
msnew(void)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 *
msrenew(char * value)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 *
msdone(struct mstring * s)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
strnscmp(const char * a,const char * b)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
strnshash(const char * s)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
mstring_leaks(void)210 mstring_leaks(void)
211 {
212     free(buf_ptr);
213     buf_ptr = 0;
214     buf_len = 0;
215 }
216 #endif
217