xref: /dflybsd-src/contrib/bmake/str.c (revision 9e7ae5a0527a977cab412aede3a532cfe2903bbb)
1*6eef5f0cSAntonio Huete Jimenez /*	$NetBSD: str.c,v 1.93 2022/06/11 09:24:07 rillig Exp $	*/
201e196c8SJohn Marino 
3a34d5fb1SAntonio Huete Jimenez /*
401e196c8SJohn Marino  * Copyright (c) 1988, 1989, 1990, 1993
501e196c8SJohn Marino  *	The Regents of the University of California.  All rights reserved.
601e196c8SJohn Marino  *
701e196c8SJohn Marino  * This code is derived from software contributed to Berkeley by
801e196c8SJohn Marino  * Adam de Boor.
901e196c8SJohn Marino  *
1001e196c8SJohn Marino  * Redistribution and use in source and binary forms, with or without
1101e196c8SJohn Marino  * modification, are permitted provided that the following conditions
1201e196c8SJohn Marino  * are met:
1301e196c8SJohn Marino  * 1. Redistributions of source code must retain the above copyright
1401e196c8SJohn Marino  *    notice, this list of conditions and the following disclaimer.
1501e196c8SJohn Marino  * 2. Redistributions in binary form must reproduce the above copyright
1601e196c8SJohn Marino  *    notice, this list of conditions and the following disclaimer in the
1701e196c8SJohn Marino  *    documentation and/or other materials provided with the distribution.
1801e196c8SJohn Marino  * 3. Neither the name of the University nor the names of its contributors
1901e196c8SJohn Marino  *    may be used to endorse or promote products derived from this software
2001e196c8SJohn Marino  *    without specific prior written permission.
2101e196c8SJohn Marino  *
2201e196c8SJohn Marino  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2301e196c8SJohn Marino  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2401e196c8SJohn Marino  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2501e196c8SJohn Marino  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2601e196c8SJohn Marino  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2701e196c8SJohn Marino  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2801e196c8SJohn Marino  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2901e196c8SJohn Marino  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3001e196c8SJohn Marino  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3101e196c8SJohn Marino  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3201e196c8SJohn Marino  * SUCH DAMAGE.
3301e196c8SJohn Marino  */
3401e196c8SJohn Marino 
35a34d5fb1SAntonio Huete Jimenez /*
3601e196c8SJohn Marino  * Copyright (c) 1989 by Berkeley Softworks
3701e196c8SJohn Marino  * All rights reserved.
3801e196c8SJohn Marino  *
3901e196c8SJohn Marino  * This code is derived from software contributed to Berkeley by
4001e196c8SJohn Marino  * Adam de Boor.
4101e196c8SJohn Marino  *
4201e196c8SJohn Marino  * Redistribution and use in source and binary forms, with or without
4301e196c8SJohn Marino  * modification, are permitted provided that the following conditions
4401e196c8SJohn Marino  * are met:
4501e196c8SJohn Marino  * 1. Redistributions of source code must retain the above copyright
4601e196c8SJohn Marino  *    notice, this list of conditions and the following disclaimer.
4701e196c8SJohn Marino  * 2. Redistributions in binary form must reproduce the above copyright
4801e196c8SJohn Marino  *    notice, this list of conditions and the following disclaimer in the
4901e196c8SJohn Marino  *    documentation and/or other materials provided with the distribution.
5001e196c8SJohn Marino  * 3. All advertising materials mentioning features or use of this software
5101e196c8SJohn Marino  *    must display the following acknowledgement:
5201e196c8SJohn Marino  *	This product includes software developed by the University of
5301e196c8SJohn Marino  *	California, Berkeley and its contributors.
5401e196c8SJohn Marino  * 4. Neither the name of the University nor the names of its contributors
5501e196c8SJohn Marino  *    may be used to endorse or promote products derived from this software
5601e196c8SJohn Marino  *    without specific prior written permission.
5701e196c8SJohn Marino  *
5801e196c8SJohn Marino  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
5901e196c8SJohn Marino  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
6001e196c8SJohn Marino  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
6101e196c8SJohn Marino  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
6201e196c8SJohn Marino  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
6301e196c8SJohn Marino  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
6401e196c8SJohn Marino  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
6501e196c8SJohn Marino  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
6601e196c8SJohn Marino  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
6701e196c8SJohn Marino  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
6801e196c8SJohn Marino  * SUCH DAMAGE.
6901e196c8SJohn Marino  */
7001e196c8SJohn Marino 
7101e196c8SJohn Marino #include "make.h"
7201e196c8SJohn Marino 
73a34d5fb1SAntonio Huete Jimenez /*	"@(#)str.c	5.8 (Berkeley) 6/1/90"	*/
74*6eef5f0cSAntonio Huete Jimenez MAKE_RCSID("$NetBSD: str.c,v 1.93 2022/06/11 09:24:07 rillig Exp $");
75*6eef5f0cSAntonio Huete Jimenez 
76*6eef5f0cSAntonio Huete Jimenez 
77*6eef5f0cSAntonio Huete Jimenez static HashTable interned_strings;
78*6eef5f0cSAntonio Huete Jimenez 
79a34d5fb1SAntonio Huete Jimenez 
80a34d5fb1SAntonio Huete Jimenez /* Return the concatenation of s1 and s2, freshly allocated. */
8101e196c8SJohn Marino char *
str_concat2(const char * s1,const char * s2)82a34d5fb1SAntonio Huete Jimenez str_concat2(const char *s1, const char *s2)
8301e196c8SJohn Marino {
84a34d5fb1SAntonio Huete Jimenez 	size_t len1 = strlen(s1);
85a34d5fb1SAntonio Huete Jimenez 	size_t len2 = strlen(s2);
86a34d5fb1SAntonio Huete Jimenez 	char *result = bmake_malloc(len1 + len2 + 1);
8701e196c8SJohn Marino 	memcpy(result, s1, len1);
8801e196c8SJohn Marino 	memcpy(result + len1, s2, len2 + 1);
89ca58f742SDaniel Fojt 	return result;
9001e196c8SJohn Marino }
9101e196c8SJohn Marino 
92a34d5fb1SAntonio Huete Jimenez /* Return the concatenation of s1, s2 and s3, freshly allocated. */
93a34d5fb1SAntonio Huete Jimenez char *
str_concat3(const char * s1,const char * s2,const char * s3)94a34d5fb1SAntonio Huete Jimenez str_concat3(const char *s1, const char *s2, const char *s3)
9501e196c8SJohn Marino {
96a34d5fb1SAntonio Huete Jimenez 	size_t len1 = strlen(s1);
97a34d5fb1SAntonio Huete Jimenez 	size_t len2 = strlen(s2);
98a34d5fb1SAntonio Huete Jimenez 	size_t len3 = strlen(s3);
99a34d5fb1SAntonio Huete Jimenez 	char *result = bmake_malloc(len1 + len2 + len3 + 1);
100a34d5fb1SAntonio Huete Jimenez 	memcpy(result, s1, len1);
101a34d5fb1SAntonio Huete Jimenez 	memcpy(result + len1, s2, len2);
102a34d5fb1SAntonio Huete Jimenez 	memcpy(result + len1 + len2, s3, len3 + 1);
103a34d5fb1SAntonio Huete Jimenez 	return result;
104a34d5fb1SAntonio Huete Jimenez }
10501e196c8SJohn Marino 
106a34d5fb1SAntonio Huete Jimenez /*
107a34d5fb1SAntonio Huete Jimenez  * Fracture a string into an array of words (as delineated by tabs or spaces)
108a34d5fb1SAntonio Huete Jimenez  * taking quotation marks into account.
109a34d5fb1SAntonio Huete Jimenez  *
110*6eef5f0cSAntonio Huete Jimenez  * If expand is true, quotes are removed and escape sequences such as \r, \t,
111a34d5fb1SAntonio Huete Jimenez  * etc... are expanded. In this case, return NULL on parse errors.
112a34d5fb1SAntonio Huete Jimenez  *
113a34d5fb1SAntonio Huete Jimenez  * Returns the fractured words, which must be freed later using Words_Free,
114a34d5fb1SAntonio Huete Jimenez  * unless the returned Words.words was NULL.
115a34d5fb1SAntonio Huete Jimenez  */
116*6eef5f0cSAntonio Huete Jimenez SubstringWords
Substring_Words(const char * str,bool expand)117*6eef5f0cSAntonio Huete Jimenez Substring_Words(const char *str, bool expand)
118a34d5fb1SAntonio Huete Jimenez {
119a34d5fb1SAntonio Huete Jimenez 	size_t str_len;
120a34d5fb1SAntonio Huete Jimenez 	char *words_buf;
121a34d5fb1SAntonio Huete Jimenez 	size_t words_cap;
122*6eef5f0cSAntonio Huete Jimenez 	Substring *words;
123a34d5fb1SAntonio Huete Jimenez 	size_t words_len;
124a34d5fb1SAntonio Huete Jimenez 	char inquote;
125a34d5fb1SAntonio Huete Jimenez 	char *word_start;
126a34d5fb1SAntonio Huete Jimenez 	char *word_end;
127a34d5fb1SAntonio Huete Jimenez 	const char *str_p;
128a34d5fb1SAntonio Huete Jimenez 
129a34d5fb1SAntonio Huete Jimenez 	/* XXX: why only hspace, not whitespace? */
130a34d5fb1SAntonio Huete Jimenez 	cpp_skip_hspace(&str);	/* skip leading space chars. */
13101e196c8SJohn Marino 
132ca58f742SDaniel Fojt 	/* words_buf holds the words, separated by '\0'. */
133ca58f742SDaniel Fojt 	str_len = strlen(str);
134a34d5fb1SAntonio Huete Jimenez 	words_buf = bmake_malloc(str_len + 1);
13501e196c8SJohn Marino 
136a34d5fb1SAntonio Huete Jimenez 	words_cap = str_len / 5 > 50 ? str_len / 5 : 50;
137*6eef5f0cSAntonio Huete Jimenez 	words = bmake_malloc((words_cap + 1) * sizeof(words[0]));
1386a91b982SJohn Marino 
1396a91b982SJohn Marino 	/*
14001e196c8SJohn Marino 	 * copy the string; at the same time, parse backslashes,
141ca58f742SDaniel Fojt 	 * quotes and build the word list.
14201e196c8SJohn Marino 	 */
143ca58f742SDaniel Fojt 	words_len = 0;
14401e196c8SJohn Marino 	inquote = '\0';
145a34d5fb1SAntonio Huete Jimenez 	word_start = words_buf;
146a34d5fb1SAntonio Huete Jimenez 	word_end = words_buf;
147a34d5fb1SAntonio Huete Jimenez 	for (str_p = str;; str_p++) {
148ca58f742SDaniel Fojt 		char ch = *str_p;
149ca58f742SDaniel Fojt 		switch (ch) {
15001e196c8SJohn Marino 		case '"':
15101e196c8SJohn Marino 		case '\'':
152a34d5fb1SAntonio Huete Jimenez 			if (inquote != '\0') {
15301e196c8SJohn Marino 				if (inquote == ch)
15401e196c8SJohn Marino 					inquote = '\0';
15501e196c8SJohn Marino 				else
15601e196c8SJohn Marino 					break;
157a34d5fb1SAntonio Huete Jimenez 			} else {
158a34d5fb1SAntonio Huete Jimenez 				inquote = ch;
15901e196c8SJohn Marino 				/* Don't miss "" or '' */
160ca58f742SDaniel Fojt 				if (word_start == NULL && str_p[1] == inquote) {
16101e196c8SJohn Marino 					if (!expand) {
162ca58f742SDaniel Fojt 						word_start = word_end;
163ca58f742SDaniel Fojt 						*word_end++ = ch;
16401e196c8SJohn Marino 					} else
165ca58f742SDaniel Fojt 						word_start = word_end + 1;
166ca58f742SDaniel Fojt 					str_p++;
16701e196c8SJohn Marino 					inquote = '\0';
16801e196c8SJohn Marino 					break;
16901e196c8SJohn Marino 				}
17001e196c8SJohn Marino 			}
17101e196c8SJohn Marino 			if (!expand) {
172ca58f742SDaniel Fojt 				if (word_start == NULL)
173ca58f742SDaniel Fojt 					word_start = word_end;
174ca58f742SDaniel Fojt 				*word_end++ = ch;
17501e196c8SJohn Marino 			}
17601e196c8SJohn Marino 			continue;
17701e196c8SJohn Marino 		case ' ':
17801e196c8SJohn Marino 		case '\t':
17901e196c8SJohn Marino 		case '\n':
180a34d5fb1SAntonio Huete Jimenez 			if (inquote != '\0')
18101e196c8SJohn Marino 				break;
182ca58f742SDaniel Fojt 			if (word_start == NULL)
18301e196c8SJohn Marino 				continue;
18401e196c8SJohn Marino 			/* FALLTHROUGH */
18501e196c8SJohn Marino 		case '\0':
18601e196c8SJohn Marino 			/*
187ca58f742SDaniel Fojt 			 * end of a token -- make sure there's enough words
18801e196c8SJohn Marino 			 * space and save off a pointer.
18901e196c8SJohn Marino 			 */
190ca58f742SDaniel Fojt 			if (word_start == NULL)
19101e196c8SJohn Marino 				goto done;
19201e196c8SJohn Marino 
193ca58f742SDaniel Fojt 			*word_end++ = '\0';
194ca58f742SDaniel Fojt 			if (words_len == words_cap) {
195*6eef5f0cSAntonio Huete Jimenez 				words_cap *= 2;
196*6eef5f0cSAntonio Huete Jimenez 				words = bmake_realloc(words,
197*6eef5f0cSAntonio Huete Jimenez 				    (words_cap + 1) * sizeof(words[0]));
19801e196c8SJohn Marino 			}
199*6eef5f0cSAntonio Huete Jimenez 			words[words_len++] =
200*6eef5f0cSAntonio Huete Jimenez 			    Substring_Init(word_start, word_end - 1);
201ca58f742SDaniel Fojt 			word_start = NULL;
20201e196c8SJohn Marino 			if (ch == '\n' || ch == '\0') {
203a34d5fb1SAntonio Huete Jimenez 				if (expand && inquote != '\0') {
204*6eef5f0cSAntonio Huete Jimenez 					SubstringWords res;
205*6eef5f0cSAntonio Huete Jimenez 
206ca58f742SDaniel Fojt 					free(words);
207ca58f742SDaniel Fojt 					free(words_buf);
208*6eef5f0cSAntonio Huete Jimenez 
209*6eef5f0cSAntonio Huete Jimenez 					res.words = NULL;
210*6eef5f0cSAntonio Huete Jimenez 					res.len = 0;
211*6eef5f0cSAntonio Huete Jimenez 					res.freeIt = NULL;
212*6eef5f0cSAntonio Huete Jimenez 					return res;
21301e196c8SJohn Marino 				}
21401e196c8SJohn Marino 				goto done;
21501e196c8SJohn Marino 			}
21601e196c8SJohn Marino 			continue;
21701e196c8SJohn Marino 		case '\\':
21801e196c8SJohn Marino 			if (!expand) {
219ca58f742SDaniel Fojt 				if (word_start == NULL)
220ca58f742SDaniel Fojt 					word_start = word_end;
221ca58f742SDaniel Fojt 				*word_end++ = '\\';
222*6eef5f0cSAntonio Huete Jimenez 				/* catch lonely '\' at end of string */
223ca58f742SDaniel Fojt 				if (str_p[1] == '\0')
22401e196c8SJohn Marino 					continue;
225ca58f742SDaniel Fojt 				ch = *++str_p;
22601e196c8SJohn Marino 				break;
22701e196c8SJohn Marino 			}
22801e196c8SJohn Marino 
229ca58f742SDaniel Fojt 			switch (ch = *++str_p) {
23001e196c8SJohn Marino 			case '\0':
23101e196c8SJohn Marino 			case '\n':
23201e196c8SJohn Marino 				/* hmmm; fix it up as best we can */
23301e196c8SJohn Marino 				ch = '\\';
234a34d5fb1SAntonio Huete Jimenez 				str_p--;
23501e196c8SJohn Marino 				break;
23601e196c8SJohn Marino 			case 'b':
23701e196c8SJohn Marino 				ch = '\b';
23801e196c8SJohn Marino 				break;
23901e196c8SJohn Marino 			case 'f':
24001e196c8SJohn Marino 				ch = '\f';
24101e196c8SJohn Marino 				break;
24201e196c8SJohn Marino 			case 'n':
24301e196c8SJohn Marino 				ch = '\n';
24401e196c8SJohn Marino 				break;
24501e196c8SJohn Marino 			case 'r':
24601e196c8SJohn Marino 				ch = '\r';
24701e196c8SJohn Marino 				break;
24801e196c8SJohn Marino 			case 't':
24901e196c8SJohn Marino 				ch = '\t';
25001e196c8SJohn Marino 				break;
25101e196c8SJohn Marino 			}
25201e196c8SJohn Marino 			break;
25301e196c8SJohn Marino 		}
254ca58f742SDaniel Fojt 		if (word_start == NULL)
255ca58f742SDaniel Fojt 			word_start = word_end;
256ca58f742SDaniel Fojt 		*word_end++ = ch;
25701e196c8SJohn Marino 	}
258a34d5fb1SAntonio Huete Jimenez done:
259*6eef5f0cSAntonio Huete Jimenez 	words[words_len] = Substring_Init(NULL, NULL);	/* useful for argv */
260*6eef5f0cSAntonio Huete Jimenez 
261*6eef5f0cSAntonio Huete Jimenez 	{
262*6eef5f0cSAntonio Huete Jimenez 		SubstringWords result;
263*6eef5f0cSAntonio Huete Jimenez 
264*6eef5f0cSAntonio Huete Jimenez 		result.words = words;
265*6eef5f0cSAntonio Huete Jimenez 		result.len = words_len;
266*6eef5f0cSAntonio Huete Jimenez 		result.freeIt = words_buf;
267*6eef5f0cSAntonio Huete Jimenez 		return result;
268*6eef5f0cSAntonio Huete Jimenez 	}
269*6eef5f0cSAntonio Huete Jimenez }
270*6eef5f0cSAntonio Huete Jimenez 
271*6eef5f0cSAntonio Huete Jimenez Words
Str_Words(const char * str,bool expand)272*6eef5f0cSAntonio Huete Jimenez Str_Words(const char *str, bool expand)
273*6eef5f0cSAntonio Huete Jimenez {
274*6eef5f0cSAntonio Huete Jimenez 	SubstringWords swords;
275*6eef5f0cSAntonio Huete Jimenez 	Words words;
276*6eef5f0cSAntonio Huete Jimenez 	size_t i;
277*6eef5f0cSAntonio Huete Jimenez 
278*6eef5f0cSAntonio Huete Jimenez 	swords = Substring_Words(str, expand);
279*6eef5f0cSAntonio Huete Jimenez 	if (swords.words == NULL) {
280*6eef5f0cSAntonio Huete Jimenez 		words.words = NULL;
281*6eef5f0cSAntonio Huete Jimenez 		words.len = 0;
282*6eef5f0cSAntonio Huete Jimenez 		words.freeIt = NULL;
283*6eef5f0cSAntonio Huete Jimenez 		return words;
284*6eef5f0cSAntonio Huete Jimenez 	}
285*6eef5f0cSAntonio Huete Jimenez 
286*6eef5f0cSAntonio Huete Jimenez 	words.words = bmake_malloc((swords.len + 1) * sizeof(words.words[0]));
287*6eef5f0cSAntonio Huete Jimenez 	words.len = swords.len;
288*6eef5f0cSAntonio Huete Jimenez 	words.freeIt = swords.freeIt;
289*6eef5f0cSAntonio Huete Jimenez 	for (i = 0; i < swords.len + 1; i++)
290*6eef5f0cSAntonio Huete Jimenez 		words.words[i] = UNCONST(swords.words[i].start);
291*6eef5f0cSAntonio Huete Jimenez 	free(swords.words);
292*6eef5f0cSAntonio Huete Jimenez 	return words;
293*6eef5f0cSAntonio Huete Jimenez }
294*6eef5f0cSAntonio Huete Jimenez 
295*6eef5f0cSAntonio Huete Jimenez /*
296*6eef5f0cSAntonio Huete Jimenez  * XXX: In the extreme edge case that one of the characters is from the basic
297*6eef5f0cSAntonio Huete Jimenez  * execution character set and the other isn't, the result of the comparison
298*6eef5f0cSAntonio Huete Jimenez  * differs depending on whether plain char is signed or unsigned.
299*6eef5f0cSAntonio Huete Jimenez  *
300*6eef5f0cSAntonio Huete Jimenez  * An example is the character range from \xE4 to 'a', where \xE4 may come
301*6eef5f0cSAntonio Huete Jimenez  * from U+00E4 'Latin small letter A with diaeresis'.
302*6eef5f0cSAntonio Huete Jimenez  *
303*6eef5f0cSAntonio Huete Jimenez  * If char is signed, \xE4 evaluates to -28, the first half of the condition
304*6eef5f0cSAntonio Huete Jimenez  * becomes -28 <= '0' && '0' <= 'a', which evaluates to true.
305*6eef5f0cSAntonio Huete Jimenez  *
306*6eef5f0cSAntonio Huete Jimenez  * If char is unsigned, \xE4 evaluates to 228, the second half of the
307*6eef5f0cSAntonio Huete Jimenez  * condition becomes 'a' <= '0' && '0' <= 228, which evaluates to false.
308*6eef5f0cSAntonio Huete Jimenez  */
309*6eef5f0cSAntonio Huete Jimenez static bool
in_range(char e1,char c,char e2)310*6eef5f0cSAntonio Huete Jimenez in_range(char e1, char c, char e2)
311*6eef5f0cSAntonio Huete Jimenez {
312*6eef5f0cSAntonio Huete Jimenez 	return (e1 <= c && c <= e2) || (e2 <= c && c <= e1);
31301e196c8SJohn Marino }
31401e196c8SJohn Marino 
31501e196c8SJohn Marino /*
316ca58f742SDaniel Fojt  * Str_Match -- Test if a string matches a pattern like "*.[ch]".
317a34d5fb1SAntonio Huete Jimenez  * The following special characters are known *?\[] (as in fnmatch(3)).
31801e196c8SJohn Marino  *
319a34d5fb1SAntonio Huete Jimenez  * XXX: this function does not detect or report malformed patterns.
320*6eef5f0cSAntonio Huete Jimenez  *
321*6eef5f0cSAntonio Huete Jimenez  * See varmod-match.mk for examples and edge cases.
32201e196c8SJohn Marino  */
323*6eef5f0cSAntonio Huete Jimenez bool
Str_Match(const char * str,const char * pat)324ca58f742SDaniel Fojt Str_Match(const char *str, const char *pat)
32501e196c8SJohn Marino {
326*6eef5f0cSAntonio Huete Jimenez 	for (; *pat != '\0'; pat++, str++) {
327*6eef5f0cSAntonio Huete Jimenez 		if (*pat == '*') {	/* match any substring */
328ca58f742SDaniel Fojt 			pat++;
329ca58f742SDaniel Fojt 			while (*pat == '*')
330ca58f742SDaniel Fojt 				pat++;
331a34d5fb1SAntonio Huete Jimenez 			if (*pat == '\0')
332*6eef5f0cSAntonio Huete Jimenez 				return true;
333*6eef5f0cSAntonio Huete Jimenez 			for (; *str != '\0'; str++)
334ca58f742SDaniel Fojt 				if (Str_Match(str, pat))
335*6eef5f0cSAntonio Huete Jimenez 					return true;
336*6eef5f0cSAntonio Huete Jimenez 			return false;
33701e196c8SJohn Marino 		}
33801e196c8SJohn Marino 
339*6eef5f0cSAntonio Huete Jimenez 		if (*str == '\0')
340*6eef5f0cSAntonio Huete Jimenez 			return false;
341ca58f742SDaniel Fojt 
342*6eef5f0cSAntonio Huete Jimenez 		if (*pat == '?')	/* match any single character */
343*6eef5f0cSAntonio Huete Jimenez 			continue;
344*6eef5f0cSAntonio Huete Jimenez 
345*6eef5f0cSAntonio Huete Jimenez 		if (*pat == '[') {	/* match a character from a list */
346*6eef5f0cSAntonio Huete Jimenez 			bool neg = pat[1] == '^';
347a34d5fb1SAntonio Huete Jimenez 			pat += neg ? 2 : 1;
348ca58f742SDaniel Fojt 
349ca58f742SDaniel Fojt 			for (;;) {
350a34d5fb1SAntonio Huete Jimenez 				if (*pat == ']' || *pat == '\0') {
351ca58f742SDaniel Fojt 					if (neg)
352ca58f742SDaniel Fojt 						break;
353*6eef5f0cSAntonio Huete Jimenez 					return false;
354ca58f742SDaniel Fojt 				}
355ca58f742SDaniel Fojt 				if (*pat == *str)
356ca58f742SDaniel Fojt 					break;
357ca58f742SDaniel Fojt 				if (pat[1] == '-') {
358a34d5fb1SAntonio Huete Jimenez 					if (pat[2] == '\0')
359ca58f742SDaniel Fojt 						return neg;
360*6eef5f0cSAntonio Huete Jimenez 					if (in_range(pat[0], *str, pat[2]))
361ca58f742SDaniel Fojt 						break;
362ca58f742SDaniel Fojt 					pat += 2;
363ca58f742SDaniel Fojt 				}
364ca58f742SDaniel Fojt 				pat++;
365ca58f742SDaniel Fojt 			}
366a34d5fb1SAntonio Huete Jimenez 			if (neg && *pat != ']' && *pat != '\0')
367*6eef5f0cSAntonio Huete Jimenez 				return false;
368a34d5fb1SAntonio Huete Jimenez 			while (*pat != ']' && *pat != '\0')
369ca58f742SDaniel Fojt 				pat++;
370a34d5fb1SAntonio Huete Jimenez 			if (*pat == '\0')
371ca58f742SDaniel Fojt 				pat--;
372*6eef5f0cSAntonio Huete Jimenez 			continue;
373ca58f742SDaniel Fojt 		}
374ca58f742SDaniel Fojt 
375*6eef5f0cSAntonio Huete Jimenez 		if (*pat == '\\')	/* match the next character exactly */
376ca58f742SDaniel Fojt 			pat++;
377ca58f742SDaniel Fojt 
378ca58f742SDaniel Fojt 		if (*pat != *str)
379*6eef5f0cSAntonio Huete Jimenez 			return false;
380ca58f742SDaniel Fojt 	}
381*6eef5f0cSAntonio Huete Jimenez 	return *str == '\0';
382*6eef5f0cSAntonio Huete Jimenez }
383*6eef5f0cSAntonio Huete Jimenez 
384*6eef5f0cSAntonio Huete Jimenez void
Str_Intern_Init(void)385*6eef5f0cSAntonio Huete Jimenez Str_Intern_Init(void)
386*6eef5f0cSAntonio Huete Jimenez {
387*6eef5f0cSAntonio Huete Jimenez 	HashTable_Init(&interned_strings);
388*6eef5f0cSAntonio Huete Jimenez }
389*6eef5f0cSAntonio Huete Jimenez 
390*6eef5f0cSAntonio Huete Jimenez void
Str_Intern_End(void)391*6eef5f0cSAntonio Huete Jimenez Str_Intern_End(void)
392*6eef5f0cSAntonio Huete Jimenez {
393*6eef5f0cSAntonio Huete Jimenez #ifdef CLEANUP
394*6eef5f0cSAntonio Huete Jimenez 	HashTable_Done(&interned_strings);
395*6eef5f0cSAntonio Huete Jimenez #endif
396*6eef5f0cSAntonio Huete Jimenez }
397*6eef5f0cSAntonio Huete Jimenez 
398*6eef5f0cSAntonio Huete Jimenez /* Return a canonical instance of str, with unlimited lifetime. */
399*6eef5f0cSAntonio Huete Jimenez const char *
Str_Intern(const char * str)400*6eef5f0cSAntonio Huete Jimenez Str_Intern(const char *str)
401*6eef5f0cSAntonio Huete Jimenez {
402*6eef5f0cSAntonio Huete Jimenez 	return HashTable_CreateEntry(&interned_strings, str, NULL)->key;
403ca58f742SDaniel Fojt }
404