1 /* $NetBSD: str.h,v 1.9 2021/05/30 21:16:54 rillig Exp $ */
4 Copyright (c) 2021 Roland Illig <rillig@NetBSD.org>
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions
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.
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.
32 * Memory-efficient string handling.
36 /* A read-only string that may need to be freed after use. */
42 /* A modifiable string that may need to be freed after use. */
43 typedef struct MFStr {
48 /* A read-only range of a character array, NOT null-terminated. */
49 typedef struct Substring {
55 * Builds a string, only allocating memory if the string is different from the
58 typedef struct LazyBuf {
66 /* The result of splitting a string into words. */
67 typedef struct Words {
73 /* The result of splitting a string into words. */
74 typedef struct SubstringWords {
82 FStr_Init(const char *str, void *freeIt)
90 /* Return a string that is the sole owner of str. */
92 FStr_InitOwn(char *str)
94 return FStr_Init(str, str);
97 /* Return a string that refers to the shared str. */
99 FStr_InitRefer(const char *str)
101 return FStr_Init(str, NULL);
105 FStr_Done(FStr *fstr)
116 MFStr_Init(char *str, void *freeIt)
120 mfstr.freeIt = freeIt;
124 /* Return a string that is the sole owner of str. */
126 MFStr_InitOwn(char *str)
128 return MFStr_Init(str, str);
131 /* Return a string that refers to the shared str. */
133 MFStr_InitRefer(char *str)
135 return MFStr_Init(str, NULL);
139 MFStr_Done(MFStr *mfstr)
144 mfstr->freeIt = NULL;
149 MAKE_STATIC Substring
150 Substring_Init(const char *start, const char *end)
159 MAKE_INLINE Substring
160 Substring_InitStr(const char *str)
162 return Substring_Init(str, str + strlen(str));
166 Substring_Length(Substring sub)
168 return (size_t)(sub.end - sub.start);
172 Substring_IsEmpty(Substring sub)
174 return sub.start == sub.end;
178 Substring_Equals(Substring sub, const char *str)
180 size_t len = strlen(str);
181 return Substring_Length(sub) == len &&
182 memcmp(sub.start, str, len) == 0;
185 MAKE_STATIC Substring
186 Substring_Sub(Substring sub, size_t start, size_t end)
188 assert(start <= Substring_Length(sub));
189 assert(end <= Substring_Length(sub));
190 return Substring_Init(sub.start + start, sub.start + end);
194 Substring_HasPrefix(Substring sub, Substring prefix)
196 return Substring_Length(sub) >= Substring_Length(prefix) &&
197 memcmp(sub.start, prefix.start, Substring_Length(prefix)) == 0;
201 Substring_HasSuffix(Substring sub, Substring suffix)
203 size_t suffixLen = Substring_Length(suffix);
204 return Substring_Length(sub) >= suffixLen &&
205 memcmp(sub.end - suffixLen, suffix.start, suffixLen) == 0;
208 /* Returns an independent, null-terminated copy of the substring. */
210 Substring_Str(Substring sub)
212 if (Substring_IsEmpty(sub))
213 return FStr_InitRefer("");
214 return FStr_InitOwn(bmake_strsedup(sub.start, sub.end));
217 MAKE_STATIC const char *
218 Substring_SkipFirst(Substring sub, char ch)
222 for (p = sub.start; p != sub.end; p++)
228 MAKE_STATIC const char *
229 Substring_LastIndex(Substring sub, char ch)
233 for (p = sub.end; p != sub.start; p--)
239 MAKE_STATIC Substring
240 Substring_Dirname(Substring pathname)
244 for (p = pathname.end; p != pathname.start; p--)
246 return Substring_Init(pathname.start, p - 1);
247 return Substring_InitStr(".");
250 MAKE_STATIC Substring
251 Substring_Basename(Substring pathname)
255 for (p = pathname.end; p != pathname.start; p--)
257 return Substring_Init(p, pathname.end);
263 LazyBuf_Init(LazyBuf *buf, const char *expected)
268 buf->expected = expected;
273 LazyBuf_Done(LazyBuf *buf)
279 LazyBuf_Add(LazyBuf *buf, char ch)
282 if (buf->data != NULL) {
283 if (buf->len == buf->cap) {
285 buf->data = bmake_realloc(buf->data, buf->cap);
287 buf->data[buf->len++] = ch;
289 } else if (ch == buf->expected[buf->len]) {
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;
302 LazyBuf_AddStr(LazyBuf *buf, const char *str)
306 for (p = str; *p != '\0'; p++)
307 LazyBuf_Add(buf, *p);
311 LazyBuf_AddBytesBetween(LazyBuf *buf, const char *start, const char *end)
315 for (p = start; p != end; p++)
316 LazyBuf_Add(buf, *p);
320 LazyBuf_AddSubstring(LazyBuf *buf, Substring sub)
322 LazyBuf_AddBytesBetween(buf, sub.start, sub.end);
325 MAKE_STATIC Substring
326 LazyBuf_Get(const LazyBuf *buf)
328 const char *start = buf->data != NULL ? buf->data : buf->expected;
329 return Substring_Init(start, start + buf->len);
333 LazyBuf_DoneGet(LazyBuf *buf)
335 if (buf->data != NULL) {
336 LazyBuf_Add(buf, '\0');
337 return FStr_InitOwn(buf->data);
339 return Substring_Str(LazyBuf_Get(buf));
343 Words Str_Words(const char *, bool);
353 SubstringWords Substring_Words(const char *, bool);
356 SubstringWords_Free(SubstringWords w)
363 char *str_concat2(const char *, const char *);
364 char *str_concat3(const char *, const char *, const char *);
366 bool Str_Match(const char *, const char *);