str.h revision 1.1 1 1.1 rillig /* $NetBSD: str.h,v 1.1 2021/04/11 12:06:53 rillig Exp $ */
2 1.1 rillig
3 1.1 rillig /*
4 1.1 rillig Copyright (c) 2021 Roland Illig <rillig (at) NetBSD.org>
5 1.1 rillig All rights reserved.
6 1.1 rillig
7 1.1 rillig Redistribution and use in source and binary forms, with or without
8 1.1 rillig modification, are permitted provided that the following conditions
9 1.1 rillig are met:
10 1.1 rillig
11 1.1 rillig 1. Redistributions of source code must retain the above copyright
12 1.1 rillig notice, this list of conditions and the following disclaimer.
13 1.1 rillig 2. Redistributions in binary form must reproduce the above copyright
14 1.1 rillig notice, this list of conditions and the following disclaimer in the
15 1.1 rillig documentation and/or other materials provided with the distribution.
16 1.1 rillig
17 1.1 rillig THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 1.1 rillig "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19 1.1 rillig TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20 1.1 rillig PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS
21 1.1 rillig BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 1.1 rillig CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 1.1 rillig SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 1.1 rillig INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 1.1 rillig CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 1.1 rillig ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 1.1 rillig POSSIBILITY OF SUCH DAMAGE.
28 1.1 rillig */
29 1.1 rillig
30 1.1 rillig
31 1.1 rillig /*
32 1.1 rillig * Memory-efficient string handling.
33 1.1 rillig */
34 1.1 rillig
35 1.1 rillig
36 1.1 rillig /* A read-only string that may need to be freed after use. */
37 1.1 rillig typedef struct FStr {
38 1.1 rillig const char *str;
39 1.1 rillig void *freeIt;
40 1.1 rillig } FStr;
41 1.1 rillig
42 1.1 rillig /* A modifiable string that may need to be freed after use. */
43 1.1 rillig typedef struct MFStr {
44 1.1 rillig char *str;
45 1.1 rillig void *freeIt;
46 1.1 rillig } MFStr;
47 1.1 rillig
48 1.1 rillig /* A read-only range of a character array, NOT null-terminated. */
49 1.1 rillig typedef struct {
50 1.1 rillig const char *start;
51 1.1 rillig const char *end;
52 1.1 rillig } Substring;
53 1.1 rillig
54 1.1 rillig /*
55 1.1 rillig * Builds a string, only allocating memory if the string is different from the
56 1.1 rillig * expected string.
57 1.1 rillig */
58 1.1 rillig typedef struct LazyBuf {
59 1.1 rillig char *data;
60 1.1 rillig size_t len;
61 1.1 rillig size_t cap;
62 1.1 rillig Substring expected;
63 1.1 rillig void *freeIt;
64 1.1 rillig } LazyBuf;
65 1.1 rillig
66 1.1 rillig /* The result of splitting a string into words. */
67 1.1 rillig typedef struct Words {
68 1.1 rillig char **words;
69 1.1 rillig size_t len;
70 1.1 rillig void *freeIt;
71 1.1 rillig } Words;
72 1.1 rillig
73 1.1 rillig
74 1.1 rillig MAKE_INLINE FStr
75 1.1 rillig FStr_Init(const char *str, void *freeIt)
76 1.1 rillig {
77 1.1 rillig FStr fstr;
78 1.1 rillig fstr.str = str;
79 1.1 rillig fstr.freeIt = freeIt;
80 1.1 rillig return fstr;
81 1.1 rillig }
82 1.1 rillig
83 1.1 rillig /* Return a string that is the sole owner of str. */
84 1.1 rillig MAKE_INLINE FStr
85 1.1 rillig FStr_InitOwn(char *str)
86 1.1 rillig {
87 1.1 rillig return FStr_Init(str, str);
88 1.1 rillig }
89 1.1 rillig
90 1.1 rillig /* Return a string that refers to the shared str. */
91 1.1 rillig MAKE_INLINE FStr
92 1.1 rillig FStr_InitRefer(const char *str)
93 1.1 rillig {
94 1.1 rillig return FStr_Init(str, NULL);
95 1.1 rillig }
96 1.1 rillig
97 1.1 rillig MAKE_INLINE void
98 1.1 rillig FStr_Done(FStr *fstr)
99 1.1 rillig {
100 1.1 rillig free(fstr->freeIt);
101 1.1 rillig #ifdef CLEANUP
102 1.1 rillig fstr->str = NULL;
103 1.1 rillig fstr->freeIt = NULL;
104 1.1 rillig #endif
105 1.1 rillig }
106 1.1 rillig
107 1.1 rillig
108 1.1 rillig MAKE_INLINE MFStr
109 1.1 rillig MFStr_Init(char *str, void *freeIt)
110 1.1 rillig {
111 1.1 rillig MFStr mfstr;
112 1.1 rillig mfstr.str = str;
113 1.1 rillig mfstr.freeIt = freeIt;
114 1.1 rillig return mfstr;
115 1.1 rillig }
116 1.1 rillig
117 1.1 rillig /* Return a string that is the sole owner of str. */
118 1.1 rillig MAKE_INLINE MFStr
119 1.1 rillig MFStr_InitOwn(char *str)
120 1.1 rillig {
121 1.1 rillig return MFStr_Init(str, str);
122 1.1 rillig }
123 1.1 rillig
124 1.1 rillig /* Return a string that refers to the shared str. */
125 1.1 rillig MAKE_INLINE MFStr
126 1.1 rillig MFStr_InitRefer(char *str)
127 1.1 rillig {
128 1.1 rillig return MFStr_Init(str, NULL);
129 1.1 rillig }
130 1.1 rillig
131 1.1 rillig MAKE_INLINE void
132 1.1 rillig MFStr_Done(MFStr *mfstr)
133 1.1 rillig {
134 1.1 rillig free(mfstr->freeIt);
135 1.1 rillig #ifdef CLEANUP
136 1.1 rillig mfstr->str = NULL;
137 1.1 rillig mfstr->freeIt = NULL;
138 1.1 rillig #endif
139 1.1 rillig }
140 1.1 rillig
141 1.1 rillig
142 1.1 rillig MAKE_INLINE Substring
143 1.1 rillig Substring_Init(const char *start, const char *end)
144 1.1 rillig {
145 1.1 rillig Substring sub;
146 1.1 rillig
147 1.1 rillig sub.start = start;
148 1.1 rillig sub.end = end;
149 1.1 rillig return sub;
150 1.1 rillig }
151 1.1 rillig
152 1.1 rillig MAKE_INLINE Substring
153 1.1 rillig Substring_InitStr(const char *str)
154 1.1 rillig {
155 1.1 rillig return Substring_Init(str, str + strlen(str));
156 1.1 rillig }
157 1.1 rillig
158 1.1 rillig MAKE_INLINE size_t
159 1.1 rillig Substring_Length(Substring sub)
160 1.1 rillig {
161 1.1 rillig return (size_t)(sub.end - sub.start);
162 1.1 rillig }
163 1.1 rillig
164 1.1 rillig MAKE_INLINE bool
165 1.1 rillig Substring_Equals(Substring sub, const char *str)
166 1.1 rillig {
167 1.1 rillig size_t len = strlen(str);
168 1.1 rillig return Substring_Length(sub) == len &&
169 1.1 rillig memcmp(sub.start, str, len) == 0;
170 1.1 rillig }
171 1.1 rillig
172 1.1 rillig MAKE_INLINE Substring
173 1.1 rillig Substring_Sub(Substring sub, size_t start, size_t end)
174 1.1 rillig {
175 1.1 rillig assert(start <= Substring_Length(sub));
176 1.1 rillig assert(end <= Substring_Length(sub));
177 1.1 rillig return Substring_Init(sub.start + start, sub.start + end);
178 1.1 rillig }
179 1.1 rillig
180 1.1 rillig MAKE_INLINE FStr
181 1.1 rillig Substring_Str(Substring sub)
182 1.1 rillig {
183 1.1 rillig return FStr_InitOwn(bmake_strsedup(sub.start, sub.end));
184 1.1 rillig }
185 1.1 rillig
186 1.1 rillig
187 1.1 rillig MAKE_INLINE void
188 1.1 rillig LazyBuf_Init(LazyBuf *buf, Substring expected)
189 1.1 rillig {
190 1.1 rillig buf->data = NULL;
191 1.1 rillig buf->len = 0;
192 1.1 rillig buf->cap = 0;
193 1.1 rillig buf->expected = expected;
194 1.1 rillig buf->freeIt = NULL;
195 1.1 rillig }
196 1.1 rillig
197 1.1 rillig MAKE_INLINE void
198 1.1 rillig LazyBuf_Done(LazyBuf *buf)
199 1.1 rillig {
200 1.1 rillig free(buf->freeIt);
201 1.1 rillig }
202 1.1 rillig
203 1.1 rillig MAKE_INLINE void
204 1.1 rillig LazyBuf_Add(LazyBuf *buf, char ch)
205 1.1 rillig {
206 1.1 rillig
207 1.1 rillig if (buf->data != NULL) {
208 1.1 rillig if (buf->len == buf->cap) {
209 1.1 rillig buf->cap *= 2;
210 1.1 rillig buf->data = bmake_realloc(buf->data, buf->cap);
211 1.1 rillig }
212 1.1 rillig buf->data[buf->len++] = ch;
213 1.1 rillig
214 1.1 rillig } else if (buf->len < Substring_Length(buf->expected) &&
215 1.1 rillig ch == buf->expected.start[buf->len]) {
216 1.1 rillig buf->len++;
217 1.1 rillig return;
218 1.1 rillig
219 1.1 rillig } else {
220 1.1 rillig buf->cap = buf->len + 16;
221 1.1 rillig buf->data = bmake_malloc(buf->cap);
222 1.1 rillig memcpy(buf->data, buf->expected.start, buf->len);
223 1.1 rillig buf->data[buf->len++] = ch;
224 1.1 rillig }
225 1.1 rillig }
226 1.1 rillig
227 1.1 rillig MAKE_INLINE void
228 1.1 rillig LazyBuf_AddStr(LazyBuf *buf, const char *str)
229 1.1 rillig {
230 1.1 rillig const char *p;
231 1.1 rillig
232 1.1 rillig for (p = str; *p != '\0'; p++)
233 1.1 rillig LazyBuf_Add(buf, *p);
234 1.1 rillig }
235 1.1 rillig
236 1.1 rillig MAKE_INLINE Substring
237 1.1 rillig LazyBuf_Get(const LazyBuf *buf)
238 1.1 rillig {
239 1.1 rillig const char *start = buf->data != NULL
240 1.1 rillig ? buf->data : buf->expected.start;
241 1.1 rillig return Substring_Init(start, start + buf->len);
242 1.1 rillig }
243 1.1 rillig
244 1.1 rillig MAKE_INLINE FStr
245 1.1 rillig LazyBuf_DoneGet(LazyBuf *buf)
246 1.1 rillig {
247 1.1 rillig if (buf->data != NULL) {
248 1.1 rillig LazyBuf_Add(buf, '\0');
249 1.1 rillig return FStr_InitOwn(buf->data);
250 1.1 rillig }
251 1.1 rillig return Substring_Str(LazyBuf_Get(buf));
252 1.1 rillig }
253 1.1 rillig
254 1.1 rillig
255 1.1 rillig Words Str_Words(const char *, bool);
256 1.1 rillig
257 1.1 rillig MAKE_INLINE void
258 1.1 rillig Words_Free(Words w)
259 1.1 rillig {
260 1.1 rillig free(w.words);
261 1.1 rillig free(w.freeIt);
262 1.1 rillig }
263 1.1 rillig
264 1.1 rillig
265 1.1 rillig char *str_concat2(const char *, const char *);
266 1.1 rillig char *str_concat3(const char *, const char *, const char *);
267 1.1 rillig char *str_concat4(const char *, const char *, const char *, const char *);
268 1.1 rillig
269 1.1 rillig bool Str_Match(const char *, const char *);
270