Home | History | Annotate | Line # | Download | only in make
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