==> src/mt.c <==1/* Strings, buffers and string lists (see the header). */
2#include "mesh/mt.h"
3
4#include <stdio.h>
5#include <stdlib.h>
6#include <string.h>
7
8static _Noreturn void oom(void) {
9 fputs("out of memory\n", stderr);
10 abort();
11}
12
13void *mt_alloc(size_t n) {
14 void *p = calloc(1, n ? n : 1);
15 if (!p) oom();
16 return p;
17}
18
19void *mt_realloc(void *p, size_t n) {
20 p = realloc(p, n ? n : 1);
21 if (!p) oom();
22 return p;
23}
24
25char *mt_strndup(const char *s, size_t n) {
26 char *d = mt_alloc(n + 1);
27 memcpy(d, s, n);
28 return d;
29}
30
31char *mt_strdup(const char *s) { return mt_strndup(s, strlen(s)); }
32
33char *mt_vfmt(const char *fmt, va_list ap) {
34 va_list c;
35 va_copy(c, ap);
36 int n = vsnprintf(NULL, 0, fmt, c);
37 va_end(c);
38 if (n < 0) return mt_strdup("");
39 char *s = mt_alloc((size_t)n + 1);
40 vsnprintf(s, (size_t)n + 1, fmt, ap);
41 return s;
42}
43
44char *mt_fmt(const char *fmt, ...) {
45 va_list ap;
46 va_start(ap, fmt);
47 char *s = mt_vfmt(fmt, ap);
48 va_end(ap);
49 return s;
50}
51
52bool mt_eq(const char *a, const char *b) { return a == b || (a && b && strcmp(a, b) == 0); }
53bool mt_starts(const char *s, const char *p) { return strncmp(s, p, strlen(p)) == 0; }
54bool mt_ends(const char *s, const char *x) {
55 size_t a = strlen(s), b = strlen(x);
56 return a >= b && memcmp(s + a - b, x, b) == 0;
57}
58bool mt_contains(const char *s, const char *n) { return strstr(s, n) != NULL; }
59
60void mt_set(char **dst, const char *src) {
61 char *n = src ? mt_strdup(src) : NULL;
62 free(*dst);
63 *dst = n;
64}
65
66void mt_putn(mt_buf *b, const char *s, size_t n) {
67 if (b->len + n + 1 > b->cap) {
68 size_t c = b->cap ? b->cap : 64;
69 while (c < b->len + n + 1) c *= 2;
70 b->s = mt_realloc(b->s, c);
71 b->cap = c;
72 }
73 memcpy(b->s + b->len, s, n);
74 b->len += n;
75 b->s[b->len] = 0;
76}
77
78void mt_puts(mt_buf *b, const char *s) { mt_putn(b, s, strlen(s)); }
79void mt_putc(mt_buf *b, char c) { mt_putn(b, &c, 1); }
80
81void mt_printf(mt_buf *b, const char *fmt, ...) {
82 va_list ap;
83 va_start(ap, fmt);
84 char *s = mt_vfmt(fmt, ap);
85 va_end(ap);
86 mt_puts(b, s);
87 free(s);
88}
89
90const char *mt_str(mt_buf *b) { return b->s ? b->s : ""; }
91
92char *mt_take(mt_buf *b) {
93 char *s = b->s ? b->s : mt_strdup("");
94 *b = (mt_buf){0};
95 return s;
96}
97
98void mt_buf_free(mt_buf *b) {
99 free(b->s);
100 *b = (mt_buf){0};
101}
102
103void mt_push_own(mt_strs *l, char *s) {
104 if (l->n == l->cap) {
105 l->cap = l->cap ? l->cap * 2 : 4;
106 l->v = mt_realloc(l->v, l->cap * sizeof *l->v);
107 }
108 l->v[l->n++] = s;
109}
110
111void mt_push(mt_strs *l, const char *s) { mt_push_own(l, mt_strdup(s)); }
112
113void mt_strs_free(mt_strs *l) {
114 for (size_t i = 0; i < l->n; i++) free(l->v[i]);
115 free(l->v);
116 *l = (mt_strs){0};
117}
118
119mt_strs mt_strs_clone(const mt_strs *l) {
120 mt_strs c = {0};
121 for (size_t i = 0; i < l->n; i++) mt_push(&c, l->v[i]);
122 return c;
123}
124
125bool mt_strs_eq(const mt_strs *a, const mt_strs *b) {
126 if (a->n != b->n) return false;
127 for (size_t i = 0; i < a->n; i++)
128 if (strcmp(a->v[i], b->v[i]) != 0) return false;
129 return true;
130}
131
132long mt_strs_find(const mt_strs *l, const char *s) {
133 for (size_t i = 0; i < l->n; i++)
134 if (strcmp(l->v[i], s) == 0) return (long)i;
135 return -1;
136}
137
138bool mt_strs_has(const mt_strs *l, const char *s) { return mt_strs_find(l, s) >= 0; }
139
140void mt_strs_remove(mt_strs *l, size_t i) {
141 free(l->v[i]);
142 memmove(l->v + i, l->v + i + 1, (l->n - i - 1) * sizeof *l->v);
143 l->n--;
144}
145
146char *mt_join(const mt_strs *l, const char *sep) {
147 mt_buf b = {0};
148 for (size_t i = 0; i < l->n; i++) {
149 if (i) mt_puts(&b, sep);
150 mt_puts(&b, l->v[i]);
151 }
152 return mt_take(&b);
153}
154
155mt_strs mt_split(const char *s, char c) {
156 mt_strs l = {0};
157 const char *p = s;
158 for (;;) {
159 const char *q = strchr(p, c);
160 if (!q) {
161 mt_push(&l, p);
162 return l;
163 }
164 mt_push_own(&l, mt_strndup(p, (size_t)(q - p)));
165 p = q + 1;
166 }
167}
168
169static bool ws(char c) { return c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\f' || c == '\v'; }
170
171mt_strs mt_words(const char *s) {
172 mt_strs l = {0};
173 const char *p = s;
174 while (*p) {
175 while (*p && ws(*p)) p++;
176 if (!*p) break;
177 const char *q = p;
178 while (*q && !ws(*q)) q++;
179 mt_push_own(&l, mt_strndup(p, (size_t)(q - p)));
180 p = q;
181 }
182 return l;
183}
184
185mt_strs mt_lines(const char *s) {
186 mt_strs l = {0};
187 const char *p = s;
188 while (*p) {
189 const char *q = strchr(p, '\n');
190 size_t n = q ? (size_t)(q - p) : strlen(p);
191 size_t k = n && p[n - 1] == '\r' ? n - 1 : n;
192 mt_push_own(&l, mt_strndup(p, k));
193 if (!q) break;
194 p = q + 1;
195 }
196 return l;
197}
198
199bool mt_split_once(const char *s, char c, char **a, char **b) {
200 const char *q = strchr(s, c);
201 if (!q) return false;
202 *a = mt_strndup(s, (size_t)(q - s));
203 *b = mt_strdup(q + 1);
204 return true;
205}
206
207char *mt_trim(const char *s) {
208 while (*s && ws(*s)) s++;
209 size_t n = strlen(s);
210 while (n && ws(s[n - 1])) n--;
211 return mt_strndup(s, n);
212}