]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/bmake/str.h
Merge commit 'acb089b983171667467adc66f56a723b609ed22e' into kbsd/vis
[FreeBSD/FreeBSD.git] / contrib / bmake / str.h
1 /*      $NetBSD: str.h,v 1.17 2023/06/23 04:56:54 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 read-only range of a character array, NOT null-terminated. */
43 typedef struct Substring {
44         const char *start;
45         const char *end;
46 } Substring;
47
48 /*
49  * Builds a string, only allocating memory if the string is different from the
50  * expected string.
51  */
52 typedef struct LazyBuf {
53         char *data;
54         size_t len;
55         size_t cap;
56         const char *expected;
57 } LazyBuf;
58
59 /* The result of splitting a string into words. */
60 typedef struct Words {
61         char **words;
62         size_t len;
63         void *freeIt;
64 } Words;
65
66 /* The result of splitting a string into words. */
67 typedef struct SubstringWords {
68         Substring *words;
69         size_t len;
70         void *freeIt;
71 } SubstringWords;
72
73 typedef struct StrMatchResult {
74         const char *error;
75         bool matched;
76 } StrMatchResult;
77
78
79 MAKE_INLINE FStr
80 FStr_Init(const char *str, void *freeIt)
81 {
82         FStr fstr;
83         fstr.str = str;
84         fstr.freeIt = freeIt;
85         return fstr;
86 }
87
88 /* Return a string that is the sole owner of str. */
89 MAKE_INLINE FStr
90 FStr_InitOwn(char *str)
91 {
92         return FStr_Init(str, str);
93 }
94
95 /* Return a string that refers to the shared str. */
96 MAKE_INLINE FStr
97 FStr_InitRefer(const char *str)
98 {
99         return FStr_Init(str, NULL);
100 }
101
102 MAKE_INLINE void
103 FStr_Done(FStr *fstr)
104 {
105         free(fstr->freeIt);
106 #ifdef CLEANUP
107         fstr->str = NULL;
108         fstr->freeIt = NULL;
109 #endif
110 }
111
112
113 MAKE_STATIC Substring
114 Substring_Init(const char *start, const char *end)
115 {
116         Substring sub;
117
118         sub.start = start;
119         sub.end = end;
120         return sub;
121 }
122
123 MAKE_INLINE Substring
124 Substring_InitStr(const char *str)
125 {
126         return Substring_Init(str, str + strlen(str));
127 }
128
129 MAKE_STATIC size_t
130 Substring_Length(Substring sub)
131 {
132         return (size_t)(sub.end - sub.start);
133 }
134
135 MAKE_STATIC bool
136 Substring_IsEmpty(Substring sub)
137 {
138         return sub.start == sub.end;
139 }
140
141 MAKE_INLINE bool
142 Substring_Equals(Substring sub, const char *str)
143 {
144         size_t len = strlen(str);
145         return Substring_Length(sub) == len &&
146                memcmp(sub.start, str, len) == 0;
147 }
148
149 MAKE_INLINE bool
150 Substring_Eq(Substring sub, Substring str)
151 {
152         size_t len = Substring_Length(sub);
153         return len == Substring_Length(str) &&
154                memcmp(sub.start, str.start, len) == 0;
155 }
156
157 MAKE_STATIC Substring
158 Substring_Sub(Substring sub, size_t start, size_t end)
159 {
160         assert(start <= Substring_Length(sub));
161         assert(end <= Substring_Length(sub));
162         return Substring_Init(sub.start + start, sub.start + end);
163 }
164
165 MAKE_STATIC bool
166 Substring_HasPrefix(Substring sub, Substring prefix)
167 {
168         return Substring_Length(sub) >= Substring_Length(prefix) &&
169                memcmp(sub.start, prefix.start, Substring_Length(prefix)) == 0;
170 }
171
172 MAKE_STATIC bool
173 Substring_HasSuffix(Substring sub, Substring suffix)
174 {
175         size_t suffixLen = Substring_Length(suffix);
176         return Substring_Length(sub) >= suffixLen &&
177                memcmp(sub.end - suffixLen, suffix.start, suffixLen) == 0;
178 }
179
180 /* Returns an independent, null-terminated copy of the substring. */
181 MAKE_STATIC FStr
182 Substring_Str(Substring sub)
183 {
184         if (Substring_IsEmpty(sub))
185                 return FStr_InitRefer("");
186         return FStr_InitOwn(bmake_strsedup(sub.start, sub.end));
187 }
188
189 MAKE_STATIC const char *
190 Substring_SkipFirst(Substring sub, char ch)
191 {
192         const char *p;
193
194         for (p = sub.start; p != sub.end; p++)
195                 if (*p == ch)
196                         return p + 1;
197         return sub.start;
198 }
199
200 MAKE_STATIC const char *
201 Substring_LastIndex(Substring sub, char ch)
202 {
203         const char *p;
204
205         for (p = sub.end; p != sub.start; p--)
206                 if (p[-1] == ch)
207                         return p - 1;
208         return NULL;
209 }
210
211 MAKE_STATIC Substring
212 Substring_Dirname(Substring pathname)
213 {
214         const char *p;
215
216         for (p = pathname.end; p != pathname.start; p--)
217                 if (p[-1] == '/')
218                         return Substring_Init(pathname.start, p - 1);
219         return Substring_InitStr(".");
220 }
221
222 MAKE_STATIC Substring
223 Substring_Basename(Substring pathname)
224 {
225         const char *p;
226
227         for (p = pathname.end; p != pathname.start; p--)
228                 if (p[-1] == '/')
229                         return Substring_Init(p, pathname.end);
230         return pathname;
231 }
232
233
234 MAKE_STATIC void
235 LazyBuf_Init(LazyBuf *buf, const char *expected)
236 {
237         buf->data = NULL;
238         buf->len = 0;
239         buf->cap = 0;
240         buf->expected = expected;
241 }
242
243 MAKE_INLINE void
244 LazyBuf_Done(LazyBuf *buf)
245 {
246         free(buf->data);
247 }
248
249 MAKE_STATIC 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 (ch == buf->expected[buf->len]) {
261                 buf->len++;
262                 return;
263
264         } else {
265                 buf->cap = buf->len + 16;
266                 buf->data = bmake_malloc(buf->cap);
267                 memcpy(buf->data, buf->expected, buf->len);
268                 buf->data[buf->len++] = ch;
269         }
270 }
271
272 MAKE_STATIC void
273 LazyBuf_AddStr(LazyBuf *buf, const char *str)
274 {
275         const char *p;
276
277         for (p = str; *p != '\0'; p++)
278                 LazyBuf_Add(buf, *p);
279 }
280
281 MAKE_INLINE void
282 LazyBuf_AddSubstring(LazyBuf *buf, Substring sub)
283 {
284         const char *p;
285
286         for (p = sub.start; p != sub.end; p++)
287                 LazyBuf_Add(buf, *p);
288 }
289
290 MAKE_STATIC Substring
291 LazyBuf_Get(const LazyBuf *buf)
292 {
293         const char *start = buf->data != NULL ? buf->data : buf->expected;
294         return Substring_Init(start, start + buf->len);
295 }
296
297 /*
298  * Returns the content of the buffer as a newly allocated string.
299  *
300  * See LazyBuf_Get to avoid unnecessary memory allocations.
301  */
302 MAKE_STATIC FStr
303 LazyBuf_DoneGet(LazyBuf *buf)
304 {
305         if (buf->data != NULL) {
306                 LazyBuf_Add(buf, '\0');
307                 return FStr_InitOwn(buf->data);
308         }
309         return Substring_Str(LazyBuf_Get(buf));
310 }
311
312
313 Words Str_Words(const char *, bool);
314
315 MAKE_INLINE void
316 Words_Free(Words w)
317 {
318         free(w.words);
319         free(w.freeIt);
320 }
321
322
323 SubstringWords Substring_Words(const char *, bool);
324
325 MAKE_INLINE void
326 SubstringWords_Init(SubstringWords *w)
327 {
328         w->words = NULL;
329         w->len = 0;
330         w->freeIt = NULL;
331 }
332
333 MAKE_INLINE void
334 SubstringWords_Free(SubstringWords w)
335 {
336         free(w.words);
337         free(w.freeIt);
338 }
339
340
341 char *str_concat2(const char *, const char *);
342 char *str_concat3(const char *, const char *, const char *);
343
344 StrMatchResult Str_Match(const char *, const char *);
345
346 void Str_Intern_Init(void);
347 void Str_Intern_End(void);
348 const char *Str_Intern(const char *);