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