Home | History | Annotate | Line # | Download | only in make
str.h revision 1.12
      1  1.12  rillig /*	$NetBSD: str.h,v 1.12 2021/12/12 13:43:47 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.4  rillig typedef struct Substring {
     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.5  rillig 	const char *expected;
     63   1.1  rillig } LazyBuf;
     64   1.1  rillig 
     65   1.1  rillig /* The result of splitting a string into words. */
     66   1.1  rillig typedef struct Words {
     67   1.1  rillig 	char **words;
     68   1.1  rillig 	size_t len;
     69   1.1  rillig 	void *freeIt;
     70   1.1  rillig } Words;
     71   1.1  rillig 
     72   1.3  rillig /* The result of splitting a string into words. */
     73   1.3  rillig typedef struct SubstringWords {
     74   1.3  rillig 	Substring *words;
     75   1.3  rillig 	size_t len;
     76   1.3  rillig 	void *freeIt;
     77   1.3  rillig } SubstringWords;
     78   1.3  rillig 
     79   1.1  rillig 
     80   1.1  rillig MAKE_INLINE FStr
     81   1.1  rillig FStr_Init(const char *str, void *freeIt)
     82   1.1  rillig {
     83   1.1  rillig 	FStr fstr;
     84   1.1  rillig 	fstr.str = str;
     85   1.1  rillig 	fstr.freeIt = freeIt;
     86   1.1  rillig 	return fstr;
     87   1.1  rillig }
     88   1.1  rillig 
     89   1.1  rillig /* Return a string that is the sole owner of str. */
     90   1.1  rillig MAKE_INLINE FStr
     91   1.1  rillig FStr_InitOwn(char *str)
     92   1.1  rillig {
     93   1.1  rillig 	return FStr_Init(str, str);
     94   1.1  rillig }
     95   1.1  rillig 
     96   1.1  rillig /* Return a string that refers to the shared str. */
     97   1.1  rillig MAKE_INLINE FStr
     98   1.1  rillig FStr_InitRefer(const char *str)
     99   1.1  rillig {
    100   1.1  rillig 	return FStr_Init(str, NULL);
    101   1.1  rillig }
    102   1.1  rillig 
    103   1.1  rillig MAKE_INLINE void
    104   1.1  rillig FStr_Done(FStr *fstr)
    105   1.1  rillig {
    106   1.1  rillig 	free(fstr->freeIt);
    107   1.1  rillig #ifdef CLEANUP
    108   1.1  rillig 	fstr->str = NULL;
    109   1.1  rillig 	fstr->freeIt = NULL;
    110   1.1  rillig #endif
    111   1.1  rillig }
    112   1.1  rillig 
    113   1.1  rillig 
    114   1.1  rillig MAKE_INLINE MFStr
    115   1.1  rillig MFStr_Init(char *str, void *freeIt)
    116   1.1  rillig {
    117   1.1  rillig 	MFStr mfstr;
    118   1.1  rillig 	mfstr.str = str;
    119   1.1  rillig 	mfstr.freeIt = freeIt;
    120   1.1  rillig 	return mfstr;
    121   1.1  rillig }
    122   1.1  rillig 
    123   1.1  rillig /* Return a string that is the sole owner of str. */
    124   1.1  rillig MAKE_INLINE MFStr
    125   1.1  rillig MFStr_InitOwn(char *str)
    126   1.1  rillig {
    127   1.1  rillig 	return MFStr_Init(str, str);
    128   1.1  rillig }
    129   1.1  rillig 
    130   1.1  rillig /* Return a string that refers to the shared str. */
    131   1.1  rillig MAKE_INLINE MFStr
    132   1.1  rillig MFStr_InitRefer(char *str)
    133   1.1  rillig {
    134   1.1  rillig 	return MFStr_Init(str, NULL);
    135   1.1  rillig }
    136   1.1  rillig 
    137   1.1  rillig MAKE_INLINE void
    138   1.1  rillig MFStr_Done(MFStr *mfstr)
    139   1.1  rillig {
    140   1.1  rillig 	free(mfstr->freeIt);
    141   1.1  rillig #ifdef CLEANUP
    142   1.1  rillig 	mfstr->str = NULL;
    143   1.1  rillig 	mfstr->freeIt = NULL;
    144   1.1  rillig #endif
    145   1.1  rillig }
    146   1.1  rillig 
    147   1.1  rillig 
    148   1.8  rillig MAKE_STATIC Substring
    149   1.1  rillig Substring_Init(const char *start, const char *end)
    150   1.1  rillig {
    151   1.1  rillig 	Substring sub;
    152   1.1  rillig 
    153   1.1  rillig 	sub.start = start;
    154   1.1  rillig 	sub.end = end;
    155   1.1  rillig 	return sub;
    156   1.1  rillig }
    157   1.1  rillig 
    158   1.1  rillig MAKE_INLINE Substring
    159   1.1  rillig Substring_InitStr(const char *str)
    160   1.1  rillig {
    161   1.1  rillig 	return Substring_Init(str, str + strlen(str));
    162   1.1  rillig }
    163   1.1  rillig 
    164   1.8  rillig MAKE_STATIC size_t
    165   1.1  rillig Substring_Length(Substring sub)
    166   1.1  rillig {
    167   1.1  rillig 	return (size_t)(sub.end - sub.start);
    168   1.1  rillig }
    169   1.1  rillig 
    170   1.8  rillig MAKE_STATIC bool
    171   1.2  rillig Substring_IsEmpty(Substring sub)
    172   1.2  rillig {
    173   1.2  rillig 	return sub.start == sub.end;
    174   1.2  rillig }
    175   1.2  rillig 
    176   1.2  rillig MAKE_INLINE bool
    177   1.1  rillig Substring_Equals(Substring sub, const char *str)
    178   1.1  rillig {
    179   1.1  rillig 	size_t len = strlen(str);
    180   1.1  rillig 	return Substring_Length(sub) == len &&
    181   1.1  rillig 	       memcmp(sub.start, str, len) == 0;
    182   1.1  rillig }
    183   1.1  rillig 
    184  1.11  rillig MAKE_INLINE bool
    185  1.11  rillig Substring_Eq(Substring sub, Substring str)
    186  1.11  rillig {
    187  1.11  rillig 	size_t len = Substring_Length(sub);
    188  1.11  rillig 	return len == Substring_Length(str) &&
    189  1.11  rillig 	       memcmp(sub.start, str.start, len) == 0;
    190  1.11  rillig }
    191  1.11  rillig 
    192   1.8  rillig MAKE_STATIC Substring
    193   1.1  rillig Substring_Sub(Substring sub, size_t start, size_t end)
    194   1.1  rillig {
    195   1.1  rillig 	assert(start <= Substring_Length(sub));
    196   1.1  rillig 	assert(end <= Substring_Length(sub));
    197   1.1  rillig 	return Substring_Init(sub.start + start, sub.start + end);
    198   1.1  rillig }
    199   1.1  rillig 
    200   1.8  rillig MAKE_STATIC bool
    201   1.6  rillig Substring_HasPrefix(Substring sub, Substring prefix)
    202   1.6  rillig {
    203   1.6  rillig 	return Substring_Length(sub) >= Substring_Length(prefix) &&
    204   1.6  rillig 	       memcmp(sub.start, prefix.start, Substring_Length(prefix)) == 0;
    205   1.6  rillig }
    206   1.6  rillig 
    207   1.8  rillig MAKE_STATIC bool
    208   1.6  rillig Substring_HasSuffix(Substring sub, Substring suffix)
    209   1.6  rillig {
    210   1.6  rillig 	size_t suffixLen = Substring_Length(suffix);
    211   1.6  rillig 	return Substring_Length(sub) >= suffixLen &&
    212   1.6  rillig 	       memcmp(sub.end - suffixLen, suffix.start, suffixLen) == 0;
    213   1.6  rillig }
    214   1.6  rillig 
    215   1.7  rillig /* Returns an independent, null-terminated copy of the substring. */
    216   1.8  rillig MAKE_STATIC FStr
    217   1.1  rillig Substring_Str(Substring sub)
    218   1.1  rillig {
    219   1.7  rillig 	if (Substring_IsEmpty(sub))
    220   1.7  rillig 		return FStr_InitRefer("");
    221   1.1  rillig 	return FStr_InitOwn(bmake_strsedup(sub.start, sub.end));
    222   1.1  rillig }
    223   1.1  rillig 
    224   1.8  rillig MAKE_STATIC const char *
    225   1.6  rillig Substring_SkipFirst(Substring sub, char ch)
    226   1.6  rillig {
    227   1.6  rillig 	const char *p;
    228   1.6  rillig 
    229   1.6  rillig 	for (p = sub.start; p != sub.end; p++)
    230   1.6  rillig 		if (*p == ch)
    231   1.6  rillig 			return p + 1;
    232   1.6  rillig 	return sub.start;
    233   1.6  rillig }
    234   1.6  rillig 
    235   1.8  rillig MAKE_STATIC const char *
    236   1.2  rillig Substring_LastIndex(Substring sub, char ch)
    237   1.2  rillig {
    238   1.2  rillig 	const char *p;
    239   1.2  rillig 
    240   1.2  rillig 	for (p = sub.end; p != sub.start; p--)
    241   1.2  rillig 		if (p[-1] == ch)
    242   1.2  rillig 			return p - 1;
    243   1.2  rillig 	return NULL;
    244   1.2  rillig }
    245   1.2  rillig 
    246   1.8  rillig MAKE_STATIC Substring
    247   1.2  rillig Substring_Dirname(Substring pathname)
    248   1.2  rillig {
    249   1.2  rillig 	const char *p;
    250   1.2  rillig 
    251   1.2  rillig 	for (p = pathname.end; p != pathname.start; p--)
    252   1.2  rillig 		if (p[-1] == '/')
    253   1.2  rillig 			return Substring_Init(pathname.start, p - 1);
    254   1.2  rillig 	return Substring_InitStr(".");
    255   1.2  rillig }
    256   1.2  rillig 
    257   1.8  rillig MAKE_STATIC Substring
    258   1.2  rillig Substring_Basename(Substring pathname)
    259   1.2  rillig {
    260   1.2  rillig 	const char *p;
    261   1.2  rillig 
    262   1.2  rillig 	for (p = pathname.end; p != pathname.start; p--)
    263   1.2  rillig 		if (p[-1] == '/')
    264   1.2  rillig 			return Substring_Init(p, pathname.end);
    265   1.2  rillig 	return pathname;
    266   1.2  rillig }
    267   1.2  rillig 
    268   1.1  rillig 
    269   1.8  rillig MAKE_STATIC void
    270   1.5  rillig LazyBuf_Init(LazyBuf *buf, const char *expected)
    271   1.1  rillig {
    272   1.1  rillig 	buf->data = NULL;
    273   1.1  rillig 	buf->len = 0;
    274   1.1  rillig 	buf->cap = 0;
    275   1.1  rillig 	buf->expected = expected;
    276   1.1  rillig }
    277   1.1  rillig 
    278   1.1  rillig MAKE_INLINE void
    279   1.1  rillig LazyBuf_Done(LazyBuf *buf)
    280   1.1  rillig {
    281  1.12  rillig 	free(buf->data);
    282   1.1  rillig }
    283   1.1  rillig 
    284   1.8  rillig MAKE_STATIC void
    285   1.1  rillig LazyBuf_Add(LazyBuf *buf, char ch)
    286   1.1  rillig {
    287   1.1  rillig 
    288   1.1  rillig 	if (buf->data != NULL) {
    289   1.1  rillig 		if (buf->len == buf->cap) {
    290   1.1  rillig 			buf->cap *= 2;
    291   1.1  rillig 			buf->data = bmake_realloc(buf->data, buf->cap);
    292   1.1  rillig 		}
    293   1.1  rillig 		buf->data[buf->len++] = ch;
    294   1.1  rillig 
    295   1.5  rillig 	} else if (ch == buf->expected[buf->len]) {
    296   1.1  rillig 		buf->len++;
    297   1.1  rillig 		return;
    298   1.1  rillig 
    299   1.1  rillig 	} else {
    300   1.1  rillig 		buf->cap = buf->len + 16;
    301   1.1  rillig 		buf->data = bmake_malloc(buf->cap);
    302   1.5  rillig 		memcpy(buf->data, buf->expected, buf->len);
    303   1.1  rillig 		buf->data[buf->len++] = ch;
    304   1.1  rillig 	}
    305   1.1  rillig }
    306   1.1  rillig 
    307   1.8  rillig MAKE_STATIC void
    308   1.1  rillig LazyBuf_AddStr(LazyBuf *buf, const char *str)
    309   1.1  rillig {
    310   1.1  rillig 	const char *p;
    311   1.1  rillig 
    312   1.1  rillig 	for (p = str; *p != '\0'; p++)
    313   1.1  rillig 		LazyBuf_Add(buf, *p);
    314   1.1  rillig }
    315   1.1  rillig 
    316   1.8  rillig MAKE_STATIC void
    317   1.4  rillig LazyBuf_AddBytesBetween(LazyBuf *buf, const char *start, const char *end)
    318   1.4  rillig {
    319   1.4  rillig 	const char *p;
    320   1.4  rillig 
    321   1.4  rillig 	for (p = start; p != end; p++)
    322   1.4  rillig 		LazyBuf_Add(buf, *p);
    323   1.4  rillig }
    324   1.4  rillig 
    325   1.4  rillig MAKE_INLINE void
    326   1.4  rillig LazyBuf_AddSubstring(LazyBuf *buf, Substring sub)
    327   1.4  rillig {
    328   1.4  rillig 	LazyBuf_AddBytesBetween(buf, sub.start, sub.end);
    329   1.4  rillig }
    330   1.4  rillig 
    331   1.8  rillig MAKE_STATIC Substring
    332   1.1  rillig LazyBuf_Get(const LazyBuf *buf)
    333   1.1  rillig {
    334   1.5  rillig 	const char *start = buf->data != NULL ? buf->data : buf->expected;
    335   1.1  rillig 	return Substring_Init(start, start + buf->len);
    336   1.1  rillig }
    337   1.1  rillig 
    338  1.12  rillig /*
    339  1.12  rillig  * Returns the content of the buffer as a newly allocated string.
    340  1.12  rillig  *
    341  1.12  rillig  * See LazyBuf_Get to avoid unnecessary memory allocations.
    342  1.12  rillig  */
    343   1.8  rillig MAKE_STATIC FStr
    344   1.1  rillig LazyBuf_DoneGet(LazyBuf *buf)
    345   1.1  rillig {
    346   1.1  rillig 	if (buf->data != NULL) {
    347   1.1  rillig 		LazyBuf_Add(buf, '\0');
    348   1.1  rillig 		return FStr_InitOwn(buf->data);
    349   1.1  rillig 	}
    350   1.1  rillig 	return Substring_Str(LazyBuf_Get(buf));
    351   1.1  rillig }
    352   1.1  rillig 
    353   1.1  rillig 
    354   1.1  rillig Words Str_Words(const char *, bool);
    355   1.1  rillig 
    356   1.1  rillig MAKE_INLINE void
    357   1.1  rillig Words_Free(Words w)
    358   1.1  rillig {
    359   1.1  rillig 	free(w.words);
    360   1.1  rillig 	free(w.freeIt);
    361   1.1  rillig }
    362   1.1  rillig 
    363   1.1  rillig 
    364   1.3  rillig SubstringWords Substring_Words(const char *, bool);
    365   1.3  rillig 
    366   1.3  rillig MAKE_INLINE void
    367  1.10  rillig SubstringWords_Init(SubstringWords *w)
    368  1.10  rillig {
    369  1.10  rillig 	w->words = NULL;
    370  1.10  rillig 	w->len = 0;
    371  1.10  rillig 	w->freeIt = NULL;
    372  1.10  rillig }
    373  1.10  rillig 
    374  1.10  rillig MAKE_INLINE void
    375   1.3  rillig SubstringWords_Free(SubstringWords w)
    376   1.3  rillig {
    377   1.3  rillig 	free(w.words);
    378   1.3  rillig 	free(w.freeIt);
    379   1.3  rillig }
    380   1.3  rillig 
    381   1.3  rillig 
    382   1.1  rillig char *str_concat2(const char *, const char *);
    383   1.1  rillig char *str_concat3(const char *, const char *, const char *);
    384   1.1  rillig 
    385   1.1  rillig bool Str_Match(const char *, const char *);
    386