summaryrefslogtreecommitdiff
path: root/src/strutil.c
blob: 919298948b1b845f7bdfba1363cff72d69bc93a8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
#include "strutil.h"

#include "arena.h"        // struct arena, new
#include <assert.h>       // assert
#include <stdarg.h>       // va_*
#include <stdbool.h>      // bool, false
#include <stdio.h>        // vsnprintf
#include <string.h>       // strlen, strncmp

int aprintf(struct arena *a, char **out, const char *fmt, ...) {
	va_list ap;
	va_start(ap, fmt);
	int ret = vaprintf(a, out, fmt, ap);
	va_end(ap);
	return ret;
}

int vaprintf(struct arena *a, char **out, const char *fmt, va_list args) {
	// Calculate size.
	va_list tmp;
	va_copy(tmp, args);
	int size = vsnprintf(NULL, 0, fmt, args);
	va_end(tmp);

	// If e.g. the format string was broken, we cannot continue.
	if (size < 0) {
		return -1;
	}

	// Arena allocation cannot fail.
	*out = new(a, char, size + 1);

	int t = vsnprintf(*out, size + 1, fmt, args);
	assert(t == size);

	return size;
}

char *joinpath(struct arena *a, const char *path_a, const char *path_b) {
	char *out;
	int ret = aprintf(a, &out, "%s/%s", path_a, path_b);
	assert(ret > 0 && "should be infallible");
	return out;
}

bool endswith(const char *haystack, const char *needle) {
	assert(haystack != NULL);
	assert(needle != NULL);

	size_t haystack_len = strlen(haystack);
	size_t needle_len = strlen(needle);

	if (needle_len > haystack_len) {
		return false;
	}

	return strncmp(haystack + (haystack_len - needle_len), needle, needle_len) == 0;
}