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