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
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
|
#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
#include <errno.h> // errno, E* macros
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;
}
char *replace_suffix(struct arena *a, const char *orig, const char *suffix, const char *with)
{
size_t orig_len = strlen(orig);
size_t suffix_len = strlen(suffix);
size_t with_len = strlen(with);
size_t new_len = orig_len - suffix_len + with_len;
char *new = new(a, char, new_len + 1);
memcpy(new, orig, orig_len - suffix_len);
memcpy(new + orig_len - suffix_len, with, with_len);
new[new_len] = '\0';
return new;
}
// Based on <https://stackoverflow.com/a/779960>
char *replace(struct arena *a, const char *orig, const char *rep, const char *with) {
assert(orig != NULL);
assert(rep != NULL);
char *tmp; // varies
size_t len_rep = strlen(rep);
if (len_rep == 0) {
errno = EINVAL; // empty rep causes infinite loop during count
return NULL;
}
size_t len_with;
if (with == NULL)
with = "";
len_with = strlen(with);
// count the number of replacements needed
const char *ins; // the next insert point
int count; // number of replacements
ins = orig;
for (count = 0; (tmp = strstr(ins, rep)) != NULL; ++count) {
ins = tmp + len_rep;
}
char *result;
tmp = result = new(a, char, strlen(orig) + (len_with - len_rep) * count + 1);
// first time through the loop, all the variable are set correctly
// from here on,
// tmp points to the end of the result string
// ins points to the next occurrence of rep in orig
// orig points to the remainder of orig after "end of rep"
while (count--) {
ins = strstr(orig, rep);
ssize_t len_front = ins - orig;
tmp = strncpy(tmp, orig, len_front) + len_front;
tmp = strcpy(tmp, with) + len_with;
orig += len_front + len_rep; // move to next "end of rep"
}
strcpy(tmp, orig);
return result;
}
|