1 /* $NetBSD: str.h,v 1.17 2023/06/23 04:56: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 read-only range of a character array, NOT null-terminated. */
43 typedef struct Substring {
49 * Builds a string, only allocating memory if the string is different from the
52 typedef struct LazyBuf {
59 /* The result of splitting a string into words. */
60 typedef struct Words {
66 /* The result of splitting a string into words. */
67 typedef struct SubstringWords {
73 typedef struct StrMatchResult {
80 FStr_Init(const char *str, void *freeIt)
88 /* Return a string that is the sole owner of str. */
90 FStr_InitOwn(char *str)
92 return FStr_Init(str, str);
95 /* Return a string that refers to the shared str. */
97 FStr_InitRefer(const char *str)
99 return FStr_Init(str, NULL);
103 FStr_Done(FStr *fstr)
113 MAKE_STATIC Substring
114 Substring_Init(const char *start, const char *end)
123 MAKE_INLINE Substring
124 Substring_InitStr(const char *str)
126 return Substring_Init(str, str + strlen(str));
130 Substring_Length(Substring sub)
132 return (size_t)(sub.end - sub.start);
136 Substring_IsEmpty(Substring sub)
138 return sub.start == sub.end;
142 Substring_Equals(Substring sub, const char *str)
144 size_t len = strlen(str);
145 return Substring_Length(sub) == len &&
146 memcmp(sub.start, str, len) == 0;
150 Substring_Eq(Substring sub, Substring str)
152 size_t len = Substring_Length(sub);
153 return len == Substring_Length(str) &&
154 memcmp(sub.start, str.start, len) == 0;
157 MAKE_STATIC Substring
158 Substring_Sub(Substring sub, size_t start, size_t end)
160 assert(start <= Substring_Length(sub));
161 assert(end <= Substring_Length(sub));
162 return Substring_Init(sub.start + start, sub.start + end);
166 Substring_HasPrefix(Substring sub, Substring prefix)
168 return Substring_Length(sub) >= Substring_Length(prefix) &&
169 memcmp(sub.start, prefix.start, Substring_Length(prefix)) == 0;
173 Substring_HasSuffix(Substring sub, Substring suffix)
175 size_t suffixLen = Substring_Length(suffix);
176 return Substring_Length(sub) >= suffixLen &&
177 memcmp(sub.end - suffixLen, suffix.start, suffixLen) == 0;
180 /* Returns an independent, null-terminated copy of the substring. */
182 Substring_Str(Substring sub)
184 if (Substring_IsEmpty(sub))
185 return FStr_InitRefer("");
186 return FStr_InitOwn(bmake_strsedup(sub.start, sub.end));
189 MAKE_STATIC const char *
190 Substring_SkipFirst(Substring sub, char ch)
194 for (p = sub.start; p != sub.end; p++)
200 MAKE_STATIC const char *
201 Substring_LastIndex(Substring sub, char ch)
205 for (p = sub.end; p != sub.start; p--)
211 MAKE_STATIC Substring
212 Substring_Dirname(Substring pathname)
216 for (p = pathname.end; p != pathname.start; p--)
218 return Substring_Init(pathname.start, p - 1);
219 return Substring_InitStr(".");
222 MAKE_STATIC Substring
223 Substring_Basename(Substring pathname)
227 for (p = pathname.end; p != pathname.start; p--)
229 return Substring_Init(p, pathname.end);
235 LazyBuf_Init(LazyBuf *buf, const char *expected)
240 buf->expected = expected;
244 LazyBuf_Done(LazyBuf *buf)
250 LazyBuf_Add(LazyBuf *buf, char ch)
253 if (buf->data != NULL) {
254 if (buf->len == buf->cap) {
256 buf->data = bmake_realloc(buf->data, buf->cap);
258 buf->data[buf->len++] = ch;
260 } else if (ch == buf->expected[buf->len]) {
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;
273 LazyBuf_AddStr(LazyBuf *buf, const char *str)
277 for (p = str; *p != '\0'; p++)
278 LazyBuf_Add(buf, *p);
282 LazyBuf_AddSubstring(LazyBuf *buf, Substring sub)
286 for (p = sub.start; p != sub.end; p++)
287 LazyBuf_Add(buf, *p);
290 MAKE_STATIC Substring
291 LazyBuf_Get(const LazyBuf *buf)
293 const char *start = buf->data != NULL ? buf->data : buf->expected;
294 return Substring_Init(start, start + buf->len);
298 * Returns the content of the buffer as a newly allocated string.
300 * See LazyBuf_Get to avoid unnecessary memory allocations.
303 LazyBuf_DoneGet(LazyBuf *buf)
305 if (buf->data != NULL) {
306 LazyBuf_Add(buf, '\0');
307 return FStr_InitOwn(buf->data);
309 return Substring_Str(LazyBuf_Get(buf));
313 Words Str_Words(const char *, bool);
323 SubstringWords Substring_Words(const char *, bool);
326 SubstringWords_Init(SubstringWords *w)
334 SubstringWords_Free(SubstringWords w)
341 char *str_concat2(const char *, const char *);
342 char *str_concat3(const char *, const char *, const char *);
344 StrMatchResult Str_Match(const char *, const char *);
346 void Str_Intern_Init(void);
347 void Str_Intern_End(void);
348 const char *Str_Intern(const char *);