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