1 /* $NetBSD: str.h,v 1.16 2022/12/05 23:41:24 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 {
75 FStr_Init(const char *str, void *freeIt)
83 /* Return a string that is the sole owner of str. */
85 FStr_InitOwn(char *str)
87 return FStr_Init(str, str);
90 /* Return a string that refers to the shared str. */
92 FStr_InitRefer(const char *str)
94 return FStr_Init(str, NULL);
108 MAKE_STATIC Substring
109 Substring_Init(const char *start, const char *end)
118 MAKE_INLINE Substring
119 Substring_InitStr(const char *str)
121 return Substring_Init(str, str + strlen(str));
125 Substring_Length(Substring sub)
127 return (size_t)(sub.end - sub.start);
131 Substring_IsEmpty(Substring sub)
133 return sub.start == sub.end;
137 Substring_Equals(Substring sub, const char *str)
139 size_t len = strlen(str);
140 return Substring_Length(sub) == len &&
141 memcmp(sub.start, str, len) == 0;
145 Substring_Eq(Substring sub, Substring str)
147 size_t len = Substring_Length(sub);
148 return len == Substring_Length(str) &&
149 memcmp(sub.start, str.start, len) == 0;
152 MAKE_STATIC Substring
153 Substring_Sub(Substring sub, size_t start, size_t end)
155 assert(start <= Substring_Length(sub));
156 assert(end <= Substring_Length(sub));
157 return Substring_Init(sub.start + start, sub.start + end);
161 Substring_HasPrefix(Substring sub, Substring prefix)
163 return Substring_Length(sub) >= Substring_Length(prefix) &&
164 memcmp(sub.start, prefix.start, Substring_Length(prefix)) == 0;
168 Substring_HasSuffix(Substring sub, Substring suffix)
170 size_t suffixLen = Substring_Length(suffix);
171 return Substring_Length(sub) >= suffixLen &&
172 memcmp(sub.end - suffixLen, suffix.start, suffixLen) == 0;
175 /* Returns an independent, null-terminated copy of the substring. */
177 Substring_Str(Substring sub)
179 if (Substring_IsEmpty(sub))
180 return FStr_InitRefer("");
181 return FStr_InitOwn(bmake_strsedup(sub.start, sub.end));
184 MAKE_STATIC const char *
185 Substring_SkipFirst(Substring sub, char ch)
189 for (p = sub.start; p != sub.end; p++)
195 MAKE_STATIC const char *
196 Substring_LastIndex(Substring sub, char ch)
200 for (p = sub.end; p != sub.start; p--)
206 MAKE_STATIC Substring
207 Substring_Dirname(Substring pathname)
211 for (p = pathname.end; p != pathname.start; p--)
213 return Substring_Init(pathname.start, p - 1);
214 return Substring_InitStr(".");
217 MAKE_STATIC Substring
218 Substring_Basename(Substring pathname)
222 for (p = pathname.end; p != pathname.start; p--)
224 return Substring_Init(p, pathname.end);
230 LazyBuf_Init(LazyBuf *buf, const char *expected)
235 buf->expected = expected;
239 LazyBuf_Done(LazyBuf *buf)
245 LazyBuf_Add(LazyBuf *buf, char ch)
248 if (buf->data != NULL) {
249 if (buf->len == buf->cap) {
251 buf->data = bmake_realloc(buf->data, buf->cap);
253 buf->data[buf->len++] = ch;
255 } else if (ch == buf->expected[buf->len]) {
260 buf->cap = buf->len + 16;
261 buf->data = bmake_malloc(buf->cap);
262 memcpy(buf->data, buf->expected, buf->len);
263 buf->data[buf->len++] = ch;
268 LazyBuf_AddStr(LazyBuf *buf, const char *str)
272 for (p = str; *p != '\0'; p++)
273 LazyBuf_Add(buf, *p);
277 LazyBuf_AddSubstring(LazyBuf *buf, Substring sub)
281 for (p = sub.start; p != sub.end; p++)
282 LazyBuf_Add(buf, *p);
285 MAKE_STATIC Substring
286 LazyBuf_Get(const LazyBuf *buf)
288 const char *start = buf->data != NULL ? buf->data : buf->expected;
289 return Substring_Init(start, start + buf->len);
293 * Returns the content of the buffer as a newly allocated string.
295 * See LazyBuf_Get to avoid unnecessary memory allocations.
298 LazyBuf_DoneGet(LazyBuf *buf)
300 if (buf->data != NULL) {
301 LazyBuf_Add(buf, '\0');
302 return FStr_InitOwn(buf->data);
304 return Substring_Str(LazyBuf_Get(buf));
308 Words Str_Words(const char *, bool);
318 SubstringWords Substring_Words(const char *, bool);
321 SubstringWords_Init(SubstringWords *w)
329 SubstringWords_Free(SubstringWords w)
336 char *str_concat2(const char *, const char *);
337 char *str_concat3(const char *, const char *, const char *);
339 bool Str_Match(const char *, const char *);
341 void Str_Intern_Init(void);
342 void Str_Intern_End(void);
343 const char *Str_Intern(const char *);