xref: /netbsd/usr.bin/make/str.h (revision 4ef78b0d)
1 /*	$NetBSD: str.h,v 1.4 2021/04/11 20:38:43 rillig Exp $	*/
2 
3 /*
4  Copyright (c) 2021 Roland Illig <rillig@NetBSD.org>
5  All rights reserved.
6 
7  Redistribution and use in source and binary forms, with or without
8  modification, are permitted provided that the following conditions
9  are met:
10 
11  1. Redistributions of source code must retain the above copyright
12     notice, this list of conditions and the following disclaimer.
13  2. Redistributions in binary form must reproduce the above copyright
14     notice, this list of conditions and the following disclaimer in the
15     documentation and/or other materials provided with the distribution.
16 
17  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19  TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS
21  BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27  POSSIBILITY OF SUCH DAMAGE.
28  */
29 
30 
31 /*
32  * Memory-efficient string handling.
33  */
34 
35 
36 /* A read-only string that may need to be freed after use. */
37 typedef struct FStr {
38 	const char *str;
39 	void *freeIt;
40 } FStr;
41 
42 /* A modifiable string that may need to be freed after use. */
43 typedef struct MFStr {
44 	char *str;
45 	void *freeIt;
46 } MFStr;
47 
48 /* A read-only range of a character array, NOT null-terminated. */
49 typedef struct Substring {
50 	const char *start;
51 	const char *end;
52 } Substring;
53 
54 /*
55  * Builds a string, only allocating memory if the string is different from the
56  * expected string.
57  */
58 typedef struct LazyBuf {
59 	char *data;
60 	size_t len;
61 	size_t cap;
62 	Substring expected;
63 	void *freeIt;
64 } LazyBuf;
65 
66 /* The result of splitting a string into words. */
67 typedef struct Words {
68 	char **words;
69 	size_t len;
70 	void *freeIt;
71 } Words;
72 
73 /* The result of splitting a string into words. */
74 typedef struct SubstringWords {
75 	Substring *words;
76 	size_t len;
77 	void *freeIt;
78 } SubstringWords;
79 
80 
81 MAKE_INLINE FStr
82 FStr_Init(const char *str, void *freeIt)
83 {
84 	FStr fstr;
85 	fstr.str = str;
86 	fstr.freeIt = freeIt;
87 	return fstr;
88 }
89 
90 /* Return a string that is the sole owner of str. */
91 MAKE_INLINE FStr
92 FStr_InitOwn(char *str)
93 {
94 	return FStr_Init(str, str);
95 }
96 
97 /* Return a string that refers to the shared str. */
98 MAKE_INLINE FStr
99 FStr_InitRefer(const char *str)
100 {
101 	return FStr_Init(str, NULL);
102 }
103 
104 MAKE_INLINE void
105 FStr_Done(FStr *fstr)
106 {
107 	free(fstr->freeIt);
108 #ifdef CLEANUP
109 	fstr->str = NULL;
110 	fstr->freeIt = NULL;
111 #endif
112 }
113 
114 
115 MAKE_INLINE MFStr
116 MFStr_Init(char *str, void *freeIt)
117 {
118 	MFStr mfstr;
119 	mfstr.str = str;
120 	mfstr.freeIt = freeIt;
121 	return mfstr;
122 }
123 
124 /* Return a string that is the sole owner of str. */
125 MAKE_INLINE MFStr
126 MFStr_InitOwn(char *str)
127 {
128 	return MFStr_Init(str, str);
129 }
130 
131 /* Return a string that refers to the shared str. */
132 MAKE_INLINE MFStr
133 MFStr_InitRefer(char *str)
134 {
135 	return MFStr_Init(str, NULL);
136 }
137 
138 MAKE_INLINE void
139 MFStr_Done(MFStr *mfstr)
140 {
141 	free(mfstr->freeIt);
142 #ifdef CLEANUP
143 	mfstr->str = NULL;
144 	mfstr->freeIt = NULL;
145 #endif
146 }
147 
148 
149 MAKE_INLINE Substring
150 Substring_Init(const char *start, const char *end)
151 {
152 	Substring sub;
153 
154 	sub.start = start;
155 	sub.end = end;
156 	return sub;
157 }
158 
159 MAKE_INLINE Substring
160 Substring_InitStr(const char *str)
161 {
162 	return Substring_Init(str, str + strlen(str));
163 }
164 
165 MAKE_INLINE size_t
166 Substring_Length(Substring sub)
167 {
168 	return (size_t)(sub.end - sub.start);
169 }
170 
171 MAKE_INLINE bool
172 Substring_IsEmpty(Substring sub)
173 {
174 	return sub.start == sub.end;
175 }
176 
177 MAKE_INLINE bool
178 Substring_Equals(Substring sub, const char *str)
179 {
180 	size_t len = strlen(str);
181 	return Substring_Length(sub) == len &&
182 	       memcmp(sub.start, str, len) == 0;
183 }
184 
185 MAKE_INLINE Substring
186 Substring_Sub(Substring sub, size_t start, size_t end)
187 {
188 	assert(start <= Substring_Length(sub));
189 	assert(end <= Substring_Length(sub));
190 	return Substring_Init(sub.start + start, sub.start + end);
191 }
192 
193 MAKE_INLINE FStr
194 Substring_Str(Substring sub)
195 {
196 	return FStr_InitOwn(bmake_strsedup(sub.start, sub.end));
197 }
198 
199 MAKE_INLINE const char *
200 Substring_LastIndex(Substring sub, char ch)
201 {
202 	const char *p;
203 
204 	for (p = sub.end; p != sub.start; p--)
205 		if (p[-1] == ch)
206 			return p - 1;
207 	return NULL;
208 }
209 
210 MAKE_INLINE Substring
211 Substring_Dirname(Substring pathname)
212 {
213 	const char *p;
214 
215 	for (p = pathname.end; p != pathname.start; p--)
216 		if (p[-1] == '/')
217 			return Substring_Init(pathname.start, p - 1);
218 	return Substring_InitStr(".");
219 }
220 
221 MAKE_INLINE Substring
222 Substring_Basename(Substring pathname)
223 {
224 	const char *p;
225 
226 	for (p = pathname.end; p != pathname.start; p--)
227 		if (p[-1] == '/')
228 			return Substring_Init(p, pathname.end);
229 	return pathname;
230 }
231 
232 
233 MAKE_INLINE void
234 LazyBuf_Init(LazyBuf *buf, Substring expected)
235 {
236 	buf->data = NULL;
237 	buf->len = 0;
238 	buf->cap = 0;
239 	buf->expected = expected;
240 	buf->freeIt = NULL;
241 }
242 
243 MAKE_INLINE void
244 LazyBuf_Done(LazyBuf *buf)
245 {
246 	free(buf->freeIt);
247 }
248 
249 MAKE_INLINE void
250 LazyBuf_Add(LazyBuf *buf, char ch)
251 {
252 
253 	if (buf->data != NULL) {
254 		if (buf->len == buf->cap) {
255 			buf->cap *= 2;
256 			buf->data = bmake_realloc(buf->data, buf->cap);
257 		}
258 		buf->data[buf->len++] = ch;
259 
260 	} else if (buf->len < Substring_Length(buf->expected) &&
261 	    ch == buf->expected.start[buf->len]) {
262 		buf->len++;
263 		return;
264 
265 	} else {
266 		buf->cap = buf->len + 16;
267 		buf->data = bmake_malloc(buf->cap);
268 		memcpy(buf->data, buf->expected.start, buf->len);
269 		buf->data[buf->len++] = ch;
270 	}
271 }
272 
273 MAKE_INLINE void
274 LazyBuf_AddStr(LazyBuf *buf, const char *str)
275 {
276 	const char *p;
277 
278 	for (p = str; *p != '\0'; p++)
279 		LazyBuf_Add(buf, *p);
280 }
281 
282 MAKE_INLINE void
283 LazyBuf_AddBytesBetween(LazyBuf *buf, const char *start, const char *end)
284 {
285 	const char *p;
286 
287 	for (p = start; p != end; p++)
288 		LazyBuf_Add(buf, *p);
289 }
290 
291 MAKE_INLINE void
292 LazyBuf_AddSubstring(LazyBuf *buf, Substring sub)
293 {
294 	LazyBuf_AddBytesBetween(buf, sub.start, sub.end);
295 }
296 
297 MAKE_INLINE Substring
298 LazyBuf_Get(const LazyBuf *buf)
299 {
300 	const char *start = buf->data != NULL
301 	    ? buf->data : buf->expected.start;
302 	return Substring_Init(start, start + buf->len);
303 }
304 
305 MAKE_INLINE FStr
306 LazyBuf_DoneGet(LazyBuf *buf)
307 {
308 	if (buf->data != NULL) {
309 		LazyBuf_Add(buf, '\0');
310 		return FStr_InitOwn(buf->data);
311 	}
312 	return Substring_Str(LazyBuf_Get(buf));
313 }
314 
315 
316 Words Str_Words(const char *, bool);
317 
318 MAKE_INLINE void
319 Words_Free(Words w)
320 {
321 	free(w.words);
322 	free(w.freeIt);
323 }
324 
325 
326 SubstringWords Substring_Words(const char *, bool);
327 
328 MAKE_INLINE void
329 SubstringWords_Free(SubstringWords w)
330 {
331 	free(w.words);
332 	free(w.freeIt);
333 }
334 
335 
336 char *str_concat2(const char *, const char *);
337 char *str_concat3(const char *, const char *, const char *);
338 char *str_concat4(const char *, const char *, const char *, const char *);
339 
340 bool Str_Match(const char *, const char *);
341