skip to content
==> 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}