Home | History | Annotate | Line # | Download | only in dist
      1 /*	$NetBSD: mstring.c,v 1.8 2026/01/18 16:41:29 christos Exp $	*/
      2 
      3 /* Id: mstring.c,v 1.11 2024/12/14 16:48:04 tom Exp  */
      4 #if HAVE_NBTOOL_CONFIG_H
      5 #include "nbtool_config.h"
      6 #endif
      7 
      8 #include <sys/cdefs.h>
      9 __RCSID("$NetBSD: mstring.c,v 1.8 2026/01/18 16:41:29 christos Exp $");
     10 
     11 #include <stdlib.h>
     12 #include <stdio.h>
     13 #include <stdarg.h>
     14 #include <ctype.h>
     15 #include <string.h>
     16 #include "defs.h"
     17 
     18 /* parameters about string length.  HEAD is the starting size and
     19 ** HEAD+TAIL should be a power of two */
     20 #define HEAD	24
     21 #define TAIL	8
     22 
     23 static char *buf_ptr;
     24 static size_t buf_len;
     25 
     26 void
     27 msprintf(struct mstring *s, const char *fmt, ...)
     28 {
     29     va_list args;
     30     size_t len;
     31 #ifdef HAVE_VSNPRINTF
     32     int changed;
     33 #endif
     34 
     35     if (!s || !s->base)
     36 	return;
     37 
     38     if (buf_len == 0)
     39     {
     40 	buf_ptr = malloc(buf_len = 4096);
     41     }
     42     if (buf_ptr == NULL)
     43     {
     44 	return;
     45     }
     46 
     47 #ifdef HAVE_VSNPRINTF
     48     do
     49     {
     50 	va_start(args, fmt);
     51 	len = (size_t)vsnprintf(buf_ptr, buf_len, fmt, args);
     52 	va_end(args);
     53 	if ((changed = (len > buf_len)) != 0)
     54 	{
     55 	    char *new_ptr = realloc(buf_ptr, (buf_len * 3) / 2);
     56 	    if (new_ptr == NULL)
     57 	    {
     58 		free(buf_ptr);
     59 		buf_ptr = NULL;
     60 		return;
     61 	    }
     62 	    buf_ptr = new_ptr;
     63 	}
     64     }
     65     while (changed);
     66 #else
     67     va_start(args, fmt);
     68     len = (size_t)vsprintf(buf_ptr, fmt, args);
     69     va_end(args);
     70     if (len >= buf_len)
     71 	return;
     72 #endif
     73 
     74     if (len > (size_t)(s->end - s->ptr))
     75     {
     76 	char *new_base;
     77 	size_t cp = (size_t)(s->ptr - s->base);
     78 	size_t cl = (size_t)(s->end - s->base);
     79 	size_t nl = cl;
     80 	while (len > (nl - cp))
     81 	    nl = nl + nl + TAIL;
     82 	if ((new_base = realloc(s->base, nl)))
     83 	{
     84 	    s->base = new_base;
     85 	    s->ptr = s->base + cp;
     86 	    s->end = s->base + nl;
     87 	}
     88 	else
     89 	{
     90 	    free(s->base);
     91 	    s->base = NULL;
     92 	    s->ptr = NULL;
     93 	    s->end = NULL;
     94 	    return;
     95 	}
     96     }
     97     memcpy(s->ptr, buf_ptr, len);
     98     s->ptr += len;
     99 }
    100 
    101 int
    102 mputchar(struct mstring *s, int ch)
    103 {
    104     if (!s || !s->base)
    105 	return ch;
    106     if (s->ptr == s->end)
    107     {
    108 	size_t len = (size_t)(s->end - s->base);
    109 	if ((s->base = realloc(s->base, len + len + TAIL)))
    110 	{
    111 	    s->ptr = s->base + len;
    112 	    s->end = s->base + len + len + TAIL;
    113 	}
    114 	else
    115 	{
    116 	    s->ptr = s->end = NULL;
    117 	    return ch;
    118 	}
    119     }
    120     *s->ptr++ = (char)ch;
    121     return ch;
    122 }
    123 
    124 struct mstring *
    125 msnew(void)
    126 {
    127     struct mstring *n = TMALLOC(struct mstring, 1);
    128 
    129     if (n)
    130     {
    131 	if ((n->base = n->ptr = MALLOC(HEAD)) != NULL)
    132 	{
    133 	    n->end = n->base + HEAD;
    134 	}
    135 	else
    136 	{
    137 	    free(n);
    138 	    n = NULL;
    139 	}
    140     }
    141     return n;
    142 }
    143 
    144 struct mstring *
    145 msrenew(char *value)
    146 {
    147     struct mstring *r = NULL;
    148     if (value != NULL)
    149     {
    150 	r = msnew();
    151 	r->base = value;
    152 	r->end = value + strlen(value);
    153 	r->ptr = r->end;
    154     }
    155     return r;
    156 }
    157 
    158 char *
    159 msdone(struct mstring *s)
    160 {
    161     char *r = NULL;
    162     if (s)
    163     {
    164 	mputc(s, 0);
    165 	r = s->base;
    166 	free(s);
    167     }
    168     return r;
    169 }
    170 
    171 #if defined(YYBTYACC)
    172 /* compare two strings, ignoring whitespace, except between two letters or
    173 ** digits (and treat all of these as equal) */
    174 int
    175 strnscmp(const char *a, const char *b)
    176 {
    177     while (1)
    178     {
    179 	while (isspace(UCH(*a)))
    180 	    a++;
    181 	while (isspace(UCH(*b)))
    182 	    b++;
    183 	while (*a && *a == *b)
    184 	    a++, b++;
    185 	if (isspace(UCH(*a)))
    186 	{
    187 	    if (isalnum(UCH(a[-1])) && isalnum(UCH(*b)))
    188 		break;
    189 	}
    190 	else if (isspace(UCH(*b)))
    191 	{
    192 	    if (isalnum(UCH(b[-1])) && isalnum(UCH(*a)))
    193 		break;
    194 	}
    195 	else
    196 	    break;
    197     }
    198     return *a - *b;
    199 }
    200 
    201 unsigned int
    202 strnshash(const char *s)
    203 {
    204     unsigned int h = 0;
    205 
    206     while (*s)
    207     {
    208 	if (!isspace(UCH(*s)))
    209 	    h = (h << 5) - h + (unsigned char)*s;
    210 	s++;
    211     }
    212     return h;
    213 }
    214 #endif
    215 
    216 #ifdef NO_LEAKS
    217 void
    218 mstring_leaks(void)
    219 {
    220     free(buf_ptr);
    221     buf_ptr = NULL;
    222     buf_len = 0;
    223 }
    224 #endif
    225