xref: /freebsd/contrib/bmake/str.h (revision 226192822cddc30cacecd55bccb48f39c653058c)
1*22619282SSimon J. Gerraty /*	$NetBSD: str.h,v 1.20 2024/07/07 07:50:57 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 read-only range of a character array, NOT null-terminated. */
43b0c40a00SSimon J. Gerraty typedef struct Substring {
44b0c40a00SSimon J. Gerraty 	const char *start;
45b0c40a00SSimon J. Gerraty 	const char *end;
46b0c40a00SSimon J. Gerraty } Substring;
47b0c40a00SSimon J. Gerraty 
48b0c40a00SSimon J. Gerraty /*
49b0c40a00SSimon J. Gerraty  * Builds a string, only allocating memory if the string is different from the
50b0c40a00SSimon J. Gerraty  * expected string.
51b0c40a00SSimon J. Gerraty  */
52b0c40a00SSimon J. Gerraty typedef struct LazyBuf {
53b0c40a00SSimon J. Gerraty 	char *data;
54b0c40a00SSimon J. Gerraty 	size_t len;
55b0c40a00SSimon J. Gerraty 	size_t cap;
56b0c40a00SSimon J. Gerraty 	const char *expected;
57b0c40a00SSimon J. Gerraty } LazyBuf;
58b0c40a00SSimon J. Gerraty 
59b0c40a00SSimon J. Gerraty /* The result of splitting a string into words. */
60b0c40a00SSimon J. Gerraty typedef struct Words {
61b0c40a00SSimon J. Gerraty 	char **words;
62b0c40a00SSimon J. Gerraty 	size_t len;
63b0c40a00SSimon J. Gerraty 	void *freeIt;
64b0c40a00SSimon J. Gerraty } Words;
65b0c40a00SSimon J. Gerraty 
66b0c40a00SSimon J. Gerraty /* The result of splitting a string into words. */
67b0c40a00SSimon J. Gerraty typedef struct SubstringWords {
68b0c40a00SSimon J. Gerraty 	Substring *words;
69b0c40a00SSimon J. Gerraty 	size_t len;
70b0c40a00SSimon J. Gerraty 	void *freeIt;
71b0c40a00SSimon J. Gerraty } SubstringWords;
72b0c40a00SSimon J. Gerraty 
73148ee845SSimon J. Gerraty typedef struct StrMatchResult {
74148ee845SSimon J. Gerraty 	const char *error;
75148ee845SSimon J. Gerraty 	bool matched;
76148ee845SSimon J. Gerraty } StrMatchResult;
77148ee845SSimon J. Gerraty 
78b0c40a00SSimon J. Gerraty 
79b0c40a00SSimon J. Gerraty /* Return a string that is the sole owner of str. */
80b0c40a00SSimon J. Gerraty MAKE_INLINE FStr
FStr_InitOwn(char * str)81b0c40a00SSimon J. Gerraty FStr_InitOwn(char *str)
82b0c40a00SSimon J. Gerraty {
83d5e0a182SSimon J. Gerraty 	FStr fstr;
84d5e0a182SSimon J. Gerraty 	fstr.str = str;
85d5e0a182SSimon J. Gerraty 	fstr.freeIt = str;
86d5e0a182SSimon J. Gerraty 	return fstr;
87b0c40a00SSimon J. Gerraty }
88b0c40a00SSimon J. Gerraty 
89b0c40a00SSimon J. Gerraty /* Return a string that refers to the shared str. */
90b0c40a00SSimon J. Gerraty MAKE_INLINE FStr
FStr_InitRefer(const char * str)91b0c40a00SSimon J. Gerraty FStr_InitRefer(const char *str)
92b0c40a00SSimon J. Gerraty {
93d5e0a182SSimon J. Gerraty 	FStr fstr;
94d5e0a182SSimon J. Gerraty 	fstr.str = str;
95d5e0a182SSimon J. Gerraty 	fstr.freeIt = NULL;
96d5e0a182SSimon J. Gerraty 	return fstr;
97b0c40a00SSimon J. Gerraty }
98b0c40a00SSimon J. Gerraty 
99b0c40a00SSimon J. Gerraty MAKE_INLINE void
FStr_Done(FStr * fstr)100b0c40a00SSimon J. Gerraty FStr_Done(FStr *fstr)
101b0c40a00SSimon J. Gerraty {
102b0c40a00SSimon J. Gerraty 	free(fstr->freeIt);
103b0c40a00SSimon J. Gerraty #ifdef CLEANUP
104b0c40a00SSimon J. Gerraty 	fstr->str = NULL;
105b0c40a00SSimon J. Gerraty 	fstr->freeIt = NULL;
106b0c40a00SSimon J. Gerraty #endif
107b0c40a00SSimon J. Gerraty }
108b0c40a00SSimon J. Gerraty 
109b0c40a00SSimon J. Gerraty 
110b0c40a00SSimon J. Gerraty MAKE_STATIC Substring
Substring_Init(const char * start,const char * end)111b0c40a00SSimon J. Gerraty Substring_Init(const char *start, const char *end)
112b0c40a00SSimon J. Gerraty {
113b0c40a00SSimon J. Gerraty 	Substring sub;
114b0c40a00SSimon J. Gerraty 
115b0c40a00SSimon J. Gerraty 	sub.start = start;
116b0c40a00SSimon J. Gerraty 	sub.end = end;
117b0c40a00SSimon J. Gerraty 	return sub;
118b0c40a00SSimon J. Gerraty }
119b0c40a00SSimon J. Gerraty 
120b0c40a00SSimon J. Gerraty MAKE_INLINE Substring
Substring_InitStr(const char * str)121b0c40a00SSimon J. Gerraty Substring_InitStr(const char *str)
122b0c40a00SSimon J. Gerraty {
123b0c40a00SSimon J. Gerraty 	return Substring_Init(str, str + strlen(str));
124b0c40a00SSimon J. Gerraty }
125b0c40a00SSimon J. Gerraty 
126b0c40a00SSimon J. Gerraty MAKE_STATIC size_t
Substring_Length(Substring sub)127b0c40a00SSimon J. Gerraty Substring_Length(Substring sub)
128b0c40a00SSimon J. Gerraty {
129b0c40a00SSimon J. Gerraty 	return (size_t)(sub.end - sub.start);
130b0c40a00SSimon J. Gerraty }
131b0c40a00SSimon J. Gerraty 
132b0c40a00SSimon J. Gerraty MAKE_STATIC bool
Substring_IsEmpty(Substring sub)133b0c40a00SSimon J. Gerraty Substring_IsEmpty(Substring sub)
134b0c40a00SSimon J. Gerraty {
135b0c40a00SSimon J. Gerraty 	return sub.start == sub.end;
136b0c40a00SSimon J. Gerraty }
137b0c40a00SSimon J. Gerraty 
138b0c40a00SSimon J. Gerraty MAKE_INLINE bool
Substring_Equals(Substring sub,const char * str)139b0c40a00SSimon J. Gerraty Substring_Equals(Substring sub, const char *str)
140b0c40a00SSimon J. Gerraty {
141b0c40a00SSimon J. Gerraty 	size_t len = strlen(str);
142b0c40a00SSimon J. Gerraty 	return Substring_Length(sub) == len &&
143b0c40a00SSimon J. Gerraty 	       memcmp(sub.start, str, len) == 0;
144b0c40a00SSimon J. Gerraty }
145b0c40a00SSimon J. Gerraty 
14612904384SSimon J. Gerraty MAKE_INLINE bool
Substring_Eq(Substring sub,Substring str)14712904384SSimon J. Gerraty Substring_Eq(Substring sub, Substring str)
14812904384SSimon J. Gerraty {
14912904384SSimon J. Gerraty 	size_t len = Substring_Length(sub);
15012904384SSimon J. Gerraty 	return len == Substring_Length(str) &&
15112904384SSimon J. Gerraty 	       memcmp(sub.start, str.start, len) == 0;
15212904384SSimon J. Gerraty }
15312904384SSimon J. Gerraty 
154b0c40a00SSimon J. Gerraty MAKE_STATIC bool
Substring_HasPrefix(Substring sub,Substring prefix)155b0c40a00SSimon J. Gerraty Substring_HasPrefix(Substring sub, Substring prefix)
156b0c40a00SSimon J. Gerraty {
157b0c40a00SSimon J. Gerraty 	return Substring_Length(sub) >= Substring_Length(prefix) &&
158b0c40a00SSimon J. Gerraty 	       memcmp(sub.start, prefix.start, Substring_Length(prefix)) == 0;
159b0c40a00SSimon J. Gerraty }
160b0c40a00SSimon J. Gerraty 
161b0c40a00SSimon J. Gerraty MAKE_STATIC bool
Substring_HasSuffix(Substring sub,Substring suffix)162b0c40a00SSimon J. Gerraty Substring_HasSuffix(Substring sub, Substring suffix)
163b0c40a00SSimon J. Gerraty {
164b0c40a00SSimon J. Gerraty 	size_t suffixLen = Substring_Length(suffix);
165b0c40a00SSimon J. Gerraty 	return Substring_Length(sub) >= suffixLen &&
166b0c40a00SSimon J. Gerraty 	       memcmp(sub.end - suffixLen, suffix.start, suffixLen) == 0;
167b0c40a00SSimon J. Gerraty }
168b0c40a00SSimon J. Gerraty 
169b0c40a00SSimon J. Gerraty /* Returns an independent, null-terminated copy of the substring. */
170b0c40a00SSimon J. Gerraty MAKE_STATIC FStr
Substring_Str(Substring sub)171b0c40a00SSimon J. Gerraty Substring_Str(Substring sub)
172b0c40a00SSimon J. Gerraty {
173b0c40a00SSimon J. Gerraty 	if (Substring_IsEmpty(sub))
174b0c40a00SSimon J. Gerraty 		return FStr_InitRefer("");
175b0c40a00SSimon J. Gerraty 	return FStr_InitOwn(bmake_strsedup(sub.start, sub.end));
176b0c40a00SSimon J. Gerraty }
177b0c40a00SSimon J. Gerraty 
178b0c40a00SSimon J. Gerraty MAKE_STATIC const char *
Substring_SkipFirst(Substring sub,char ch)179b0c40a00SSimon J. Gerraty Substring_SkipFirst(Substring sub, char ch)
180b0c40a00SSimon J. Gerraty {
181b0c40a00SSimon J. Gerraty 	const char *p;
182b0c40a00SSimon J. Gerraty 
183b0c40a00SSimon J. Gerraty 	for (p = sub.start; p != sub.end; p++)
184b0c40a00SSimon J. Gerraty 		if (*p == ch)
185b0c40a00SSimon J. Gerraty 			return p + 1;
186b0c40a00SSimon J. Gerraty 	return sub.start;
187b0c40a00SSimon J. Gerraty }
188b0c40a00SSimon J. Gerraty 
189b0c40a00SSimon J. Gerraty MAKE_STATIC const char *
Substring_FindLast(Substring sub,char ch)190d5e0a182SSimon J. Gerraty Substring_FindLast(Substring sub, char ch)
191b0c40a00SSimon J. Gerraty {
192b0c40a00SSimon J. Gerraty 	const char *p;
193b0c40a00SSimon J. Gerraty 
194b0c40a00SSimon J. Gerraty 	for (p = sub.end; p != sub.start; p--)
195b0c40a00SSimon J. Gerraty 		if (p[-1] == ch)
196b0c40a00SSimon J. Gerraty 			return p - 1;
197b0c40a00SSimon J. Gerraty 	return NULL;
198b0c40a00SSimon J. Gerraty }
199b0c40a00SSimon J. Gerraty 
200b0c40a00SSimon J. Gerraty MAKE_STATIC Substring
Substring_Dirname(Substring pathname)201b0c40a00SSimon J. Gerraty Substring_Dirname(Substring pathname)
202b0c40a00SSimon J. Gerraty {
203b0c40a00SSimon J. Gerraty 	const char *p;
204b0c40a00SSimon J. Gerraty 
205b0c40a00SSimon J. Gerraty 	for (p = pathname.end; p != pathname.start; p--)
206b0c40a00SSimon J. Gerraty 		if (p[-1] == '/')
207b0c40a00SSimon J. Gerraty 			return Substring_Init(pathname.start, p - 1);
208b0c40a00SSimon J. Gerraty 	return Substring_InitStr(".");
209b0c40a00SSimon J. Gerraty }
210b0c40a00SSimon J. Gerraty 
211b0c40a00SSimon J. Gerraty MAKE_STATIC Substring
Substring_Basename(Substring pathname)212b0c40a00SSimon J. Gerraty Substring_Basename(Substring pathname)
213b0c40a00SSimon J. Gerraty {
214b0c40a00SSimon J. Gerraty 	const char *p;
215b0c40a00SSimon J. Gerraty 
216b0c40a00SSimon J. Gerraty 	for (p = pathname.end; p != pathname.start; p--)
217b0c40a00SSimon J. Gerraty 		if (p[-1] == '/')
218b0c40a00SSimon J. Gerraty 			return Substring_Init(p, pathname.end);
219b0c40a00SSimon J. Gerraty 	return pathname;
220b0c40a00SSimon J. Gerraty }
221b0c40a00SSimon J. Gerraty 
222b0c40a00SSimon J. Gerraty 
223b0c40a00SSimon J. Gerraty MAKE_STATIC void
LazyBuf_Init(LazyBuf * buf,const char * expected)224b0c40a00SSimon J. Gerraty LazyBuf_Init(LazyBuf *buf, const char *expected)
225b0c40a00SSimon J. Gerraty {
226b0c40a00SSimon J. Gerraty 	buf->data = NULL;
227b0c40a00SSimon J. Gerraty 	buf->len = 0;
228b0c40a00SSimon J. Gerraty 	buf->cap = 0;
229b0c40a00SSimon J. Gerraty 	buf->expected = expected;
230b0c40a00SSimon J. Gerraty }
231b0c40a00SSimon J. Gerraty 
232b0c40a00SSimon J. Gerraty MAKE_INLINE void
LazyBuf_Done(LazyBuf * buf)233b0c40a00SSimon J. Gerraty LazyBuf_Done(LazyBuf *buf)
234b0c40a00SSimon J. Gerraty {
23512904384SSimon J. Gerraty 	free(buf->data);
236b0c40a00SSimon J. Gerraty }
237b0c40a00SSimon J. Gerraty 
238b0c40a00SSimon J. Gerraty MAKE_STATIC void
LazyBuf_Add(LazyBuf * buf,char ch)239b0c40a00SSimon J. Gerraty LazyBuf_Add(LazyBuf *buf, char ch)
240b0c40a00SSimon J. Gerraty {
241b0c40a00SSimon J. Gerraty 
242b0c40a00SSimon J. Gerraty 	if (buf->data != NULL) {
243b0c40a00SSimon J. Gerraty 		if (buf->len == buf->cap) {
244b0c40a00SSimon J. Gerraty 			buf->cap *= 2;
245b0c40a00SSimon J. Gerraty 			buf->data = bmake_realloc(buf->data, buf->cap);
246b0c40a00SSimon J. Gerraty 		}
247b0c40a00SSimon J. Gerraty 		buf->data[buf->len++] = ch;
248b0c40a00SSimon J. Gerraty 
249b0c40a00SSimon J. Gerraty 	} else if (ch == buf->expected[buf->len]) {
250b0c40a00SSimon J. Gerraty 		buf->len++;
251b0c40a00SSimon J. Gerraty 		return;
252b0c40a00SSimon J. Gerraty 
253b0c40a00SSimon J. Gerraty 	} else {
254b0c40a00SSimon J. Gerraty 		buf->cap = buf->len + 16;
255b0c40a00SSimon J. Gerraty 		buf->data = bmake_malloc(buf->cap);
256b0c40a00SSimon J. Gerraty 		memcpy(buf->data, buf->expected, buf->len);
257b0c40a00SSimon J. Gerraty 		buf->data[buf->len++] = ch;
258b0c40a00SSimon J. Gerraty 	}
259b0c40a00SSimon J. Gerraty }
260b0c40a00SSimon J. Gerraty 
261b0c40a00SSimon J. Gerraty MAKE_STATIC void
LazyBuf_AddStr(LazyBuf * buf,const char * str)262b0c40a00SSimon J. Gerraty LazyBuf_AddStr(LazyBuf *buf, const char *str)
263b0c40a00SSimon J. Gerraty {
264b0c40a00SSimon J. Gerraty 	const char *p;
265b0c40a00SSimon J. Gerraty 
266b0c40a00SSimon J. Gerraty 	for (p = str; *p != '\0'; p++)
267b0c40a00SSimon J. Gerraty 		LazyBuf_Add(buf, *p);
268b0c40a00SSimon J. Gerraty }
269b0c40a00SSimon J. Gerraty 
270b0c40a00SSimon J. Gerraty MAKE_INLINE void
LazyBuf_AddSubstring(LazyBuf * buf,Substring sub)271b0c40a00SSimon J. Gerraty LazyBuf_AddSubstring(LazyBuf *buf, Substring sub)
272b0c40a00SSimon J. Gerraty {
2734fde40d9SSimon J. Gerraty 	const char *p;
2744fde40d9SSimon J. Gerraty 
2754fde40d9SSimon J. Gerraty 	for (p = sub.start; p != sub.end; p++)
2764fde40d9SSimon J. Gerraty 		LazyBuf_Add(buf, *p);
277b0c40a00SSimon J. Gerraty }
278b0c40a00SSimon J. Gerraty 
279b0c40a00SSimon J. Gerraty MAKE_STATIC Substring
LazyBuf_Get(const LazyBuf * buf)280b0c40a00SSimon J. Gerraty LazyBuf_Get(const LazyBuf *buf)
281b0c40a00SSimon J. Gerraty {
282b0c40a00SSimon J. Gerraty 	const char *start = buf->data != NULL ? buf->data : buf->expected;
283b0c40a00SSimon J. Gerraty 	return Substring_Init(start, start + buf->len);
284b0c40a00SSimon J. Gerraty }
285b0c40a00SSimon J. Gerraty 
28612904384SSimon J. Gerraty /*
28712904384SSimon J. Gerraty  * Returns the content of the buffer as a newly allocated string.
28812904384SSimon J. Gerraty  *
28912904384SSimon J. Gerraty  * See LazyBuf_Get to avoid unnecessary memory allocations.
29012904384SSimon J. Gerraty  */
291b0c40a00SSimon J. Gerraty MAKE_STATIC FStr
LazyBuf_DoneGet(LazyBuf * buf)292b0c40a00SSimon J. Gerraty LazyBuf_DoneGet(LazyBuf *buf)
293b0c40a00SSimon J. Gerraty {
294b0c40a00SSimon J. Gerraty 	if (buf->data != NULL) {
295b0c40a00SSimon J. Gerraty 		LazyBuf_Add(buf, '\0');
296b0c40a00SSimon J. Gerraty 		return FStr_InitOwn(buf->data);
297b0c40a00SSimon J. Gerraty 	}
298b0c40a00SSimon J. Gerraty 	return Substring_Str(LazyBuf_Get(buf));
299b0c40a00SSimon J. Gerraty }
300b0c40a00SSimon J. Gerraty 
301b0c40a00SSimon J. Gerraty 
302b0c40a00SSimon J. Gerraty Words Str_Words(const char *, bool);
303b0c40a00SSimon J. Gerraty 
304b0c40a00SSimon J. Gerraty MAKE_INLINE void
Words_Free(Words w)305b0c40a00SSimon J. Gerraty Words_Free(Words w)
306b0c40a00SSimon J. Gerraty {
307b0c40a00SSimon J. Gerraty 	free(w.words);
308b0c40a00SSimon J. Gerraty 	free(w.freeIt);
309b0c40a00SSimon J. Gerraty }
310b0c40a00SSimon J. Gerraty 
311b0c40a00SSimon J. Gerraty 
312b0c40a00SSimon J. Gerraty SubstringWords Substring_Words(const char *, bool);
313b0c40a00SSimon J. Gerraty 
314b0c40a00SSimon J. Gerraty MAKE_INLINE void
SubstringWords_Init(SubstringWords * w)31512904384SSimon J. Gerraty SubstringWords_Init(SubstringWords *w)
31612904384SSimon J. Gerraty {
31712904384SSimon J. Gerraty 	w->words = NULL;
31812904384SSimon J. Gerraty 	w->len = 0;
31912904384SSimon J. Gerraty 	w->freeIt = NULL;
32012904384SSimon J. Gerraty }
32112904384SSimon J. Gerraty 
32212904384SSimon J. Gerraty MAKE_INLINE void
SubstringWords_Free(SubstringWords w)323b0c40a00SSimon J. Gerraty SubstringWords_Free(SubstringWords w)
324b0c40a00SSimon J. Gerraty {
325b0c40a00SSimon J. Gerraty 	free(w.words);
326b0c40a00SSimon J. Gerraty 	free(w.freeIt);
327b0c40a00SSimon J. Gerraty }
328b0c40a00SSimon J. Gerraty 
329b0c40a00SSimon J. Gerraty 
330b0c40a00SSimon J. Gerraty char *str_concat2(const char *, const char *);
331b0c40a00SSimon J. Gerraty char *str_concat3(const char *, const char *, const char *);
332b0c40a00SSimon J. Gerraty 
333148ee845SSimon J. Gerraty StrMatchResult Str_Match(const char *, const char *);
3349f45a3c8SSimon J. Gerraty 
3359f45a3c8SSimon J. Gerraty void Str_Intern_Init(void);
336*22619282SSimon J. Gerraty #ifdef CLEANUP
3379f45a3c8SSimon J. Gerraty void Str_Intern_End(void);
338*22619282SSimon J. Gerraty #endif
3399f45a3c8SSimon J. Gerraty const char *Str_Intern(const char *);
340