str.h revision 1.1 1 /* $NetBSD: str.h,v 1.1 2021/04/11 12:06:53 rillig Exp $ */
2
3 /*
4 Copyright (c) 2021 Roland Illig <rillig (at) 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 {
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 Substring 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
74 MAKE_INLINE FStr
75 FStr_Init(const char *str, void *freeIt)
76 {
77 FStr fstr;
78 fstr.str = str;
79 fstr.freeIt = freeIt;
80 return fstr;
81 }
82
83 /* Return a string that is the sole owner of str. */
84 MAKE_INLINE FStr
85 FStr_InitOwn(char *str)
86 {
87 return FStr_Init(str, str);
88 }
89
90 /* Return a string that refers to the shared str. */
91 MAKE_INLINE FStr
92 FStr_InitRefer(const char *str)
93 {
94 return FStr_Init(str, NULL);
95 }
96
97 MAKE_INLINE void
98 FStr_Done(FStr *fstr)
99 {
100 free(fstr->freeIt);
101 #ifdef CLEANUP
102 fstr->str = NULL;
103 fstr->freeIt = NULL;
104 #endif
105 }
106
107
108 MAKE_INLINE MFStr
109 MFStr_Init(char *str, void *freeIt)
110 {
111 MFStr mfstr;
112 mfstr.str = str;
113 mfstr.freeIt = freeIt;
114 return mfstr;
115 }
116
117 /* Return a string that is the sole owner of str. */
118 MAKE_INLINE MFStr
119 MFStr_InitOwn(char *str)
120 {
121 return MFStr_Init(str, str);
122 }
123
124 /* Return a string that refers to the shared str. */
125 MAKE_INLINE MFStr
126 MFStr_InitRefer(char *str)
127 {
128 return MFStr_Init(str, NULL);
129 }
130
131 MAKE_INLINE void
132 MFStr_Done(MFStr *mfstr)
133 {
134 free(mfstr->freeIt);
135 #ifdef CLEANUP
136 mfstr->str = NULL;
137 mfstr->freeIt = NULL;
138 #endif
139 }
140
141
142 MAKE_INLINE Substring
143 Substring_Init(const char *start, const char *end)
144 {
145 Substring sub;
146
147 sub.start = start;
148 sub.end = end;
149 return sub;
150 }
151
152 MAKE_INLINE Substring
153 Substring_InitStr(const char *str)
154 {
155 return Substring_Init(str, str + strlen(str));
156 }
157
158 MAKE_INLINE size_t
159 Substring_Length(Substring sub)
160 {
161 return (size_t)(sub.end - sub.start);
162 }
163
164 MAKE_INLINE bool
165 Substring_Equals(Substring sub, const char *str)
166 {
167 size_t len = strlen(str);
168 return Substring_Length(sub) == len &&
169 memcmp(sub.start, str, len) == 0;
170 }
171
172 MAKE_INLINE Substring
173 Substring_Sub(Substring sub, size_t start, size_t end)
174 {
175 assert(start <= Substring_Length(sub));
176 assert(end <= Substring_Length(sub));
177 return Substring_Init(sub.start + start, sub.start + end);
178 }
179
180 MAKE_INLINE FStr
181 Substring_Str(Substring sub)
182 {
183 return FStr_InitOwn(bmake_strsedup(sub.start, sub.end));
184 }
185
186
187 MAKE_INLINE void
188 LazyBuf_Init(LazyBuf *buf, Substring expected)
189 {
190 buf->data = NULL;
191 buf->len = 0;
192 buf->cap = 0;
193 buf->expected = expected;
194 buf->freeIt = NULL;
195 }
196
197 MAKE_INLINE void
198 LazyBuf_Done(LazyBuf *buf)
199 {
200 free(buf->freeIt);
201 }
202
203 MAKE_INLINE void
204 LazyBuf_Add(LazyBuf *buf, char ch)
205 {
206
207 if (buf->data != NULL) {
208 if (buf->len == buf->cap) {
209 buf->cap *= 2;
210 buf->data = bmake_realloc(buf->data, buf->cap);
211 }
212 buf->data[buf->len++] = ch;
213
214 } else if (buf->len < Substring_Length(buf->expected) &&
215 ch == buf->expected.start[buf->len]) {
216 buf->len++;
217 return;
218
219 } else {
220 buf->cap = buf->len + 16;
221 buf->data = bmake_malloc(buf->cap);
222 memcpy(buf->data, buf->expected.start, buf->len);
223 buf->data[buf->len++] = ch;
224 }
225 }
226
227 MAKE_INLINE void
228 LazyBuf_AddStr(LazyBuf *buf, const char *str)
229 {
230 const char *p;
231
232 for (p = str; *p != '\0'; p++)
233 LazyBuf_Add(buf, *p);
234 }
235
236 MAKE_INLINE Substring
237 LazyBuf_Get(const LazyBuf *buf)
238 {
239 const char *start = buf->data != NULL
240 ? buf->data : buf->expected.start;
241 return Substring_Init(start, start + buf->len);
242 }
243
244 MAKE_INLINE FStr
245 LazyBuf_DoneGet(LazyBuf *buf)
246 {
247 if (buf->data != NULL) {
248 LazyBuf_Add(buf, '\0');
249 return FStr_InitOwn(buf->data);
250 }
251 return Substring_Str(LazyBuf_Get(buf));
252 }
253
254
255 Words Str_Words(const char *, bool);
256
257 MAKE_INLINE void
258 Words_Free(Words w)
259 {
260 free(w.words);
261 free(w.freeIt);
262 }
263
264
265 char *str_concat2(const char *, const char *);
266 char *str_concat3(const char *, const char *, const char *);
267 char *str_concat4(const char *, const char *, const char *, const char *);
268
269 bool Str_Match(const char *, const char *);
270