-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathstring_utils.c
147 lines (133 loc) · 4.35 KB
/
string_utils.c
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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
#include "string_utils.h"
#include <assert.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
bool string_starts_with(const char* string, const char* start) {
return (strncmp(string, start, strlen(start)) == 0);
}
bool string_ends_with(const char* string, const char* ending) {
const int string_length = strlen(string);
const int ending_length = strlen(ending);
if (string_length < ending_length) {
return false;
}
for (int i = 0; i < ending_length; ++i) {
const int string_index = (string_length - (i + 1));
const int ending_index = (ending_length - (i + 1));
const char string_char = string[string_index];
const char ending_char = ending[ending_index];
if (string_char != ending_char) {
return false;
}
}
return true;
}
char* string_duplicate(const char* source) {
if (source == NULL) {
return NULL;
}
const int length = strlen(source);
char* result = malloc(length + 1);
strncpy(result, source, length + 1);
return result;
}
char* string_alloc_sprintf(const char* format, ...) {
va_list args;
va_start(args, format);
va_list args_copy;
va_copy(args_copy, args);
size_t size = vsnprintf(NULL, 0, format, args) + 1;
va_end(args);
char* result = malloc(size);
vsnprintf(result, size, format, args_copy);
va_end(args_copy);
return result;
}
// Splits a string into multiple parts, based on the single-character separator.
// The `max_splits` arguments controls the maximum number of parts that will be
// produced, or -1 for no maximum. The caller is responsible for calling free()
// on the `outputs` array, and for all of the entries in that array.
void string_split(const char* input, char separator, const int max_splits,
char*** outputs, int* outputs_length) {
assert(input != NULL);
const int input_length = strlen(input);
*outputs = NULL;
*outputs_length = 0;
int last_split_index = 0;
for (int i = 0; i < input_length; ++i) {
const char current = input[i];
if ((current == separator) &&
((max_splits == -1) || (*outputs_length < (max_splits - 1)))) {
const int split_length = (i - last_split_index);
char* split = malloc(split_length + 1);
for (int j = 0; j < split_length; ++j) {
split[j] = input[last_split_index + j];
}
split[split_length] = 0;
*outputs = realloc(*outputs, (*outputs_length + 1) * sizeof(char*));
(*outputs)[*outputs_length] = split;
*outputs_length += 1;
last_split_index = i + 1;
}
}
const int split_length = (input_length - last_split_index);
if (split_length > 0) {
char* split = malloc(split_length + 1);
for (int j = 0; j < split_length; ++j) {
split[j] = input[last_split_index + j];
}
split[split_length] = 0;
*outputs = realloc(*outputs, (*outputs_length + 1) * sizeof(char*));
(*outputs)[*outputs_length] = split;
*outputs_length += 1;
}
}
void string_list_free(char** list, int list_length) {
for (int i = 0; i < list_length; ++i) {
free(list[i]);
}
free(list);
}
void string_list_add(const char* new, char*** list, int* list_length) {
*list = realloc(*list, (*list_length + 1) * sizeof(char*));
(*list)[*list_length] = string_duplicate(new);
*list_length += 1;
}
char* string_append(const char* a, const char* b) {
return string_alloc_sprintf("%s%s", a, b);
}
char* string_append_in_place(char* a, const char* b) {
char* result = string_alloc_sprintf("%s%s", a, b);
free(a);
return result;
}
char* string_join(const char** list, int list_length, const char* separator) {
char* current = string_duplicate("");
for (int i = 0; i < list_length; ++i) {
char* next = string_append(current, list[i]);
free(current);
current = next;
if (i < (list_length - 1)) {
char* next = string_append(current, separator);
free(current);
current = next;
}
}
return current;
}
void string_list_filter(const char** in_list, int in_list_length,
string_list_filter_funcptr should_keep_func, void* cookie, char*** out_list,
int* out_list_length) {
*out_list = NULL;
*out_list_length = 0;
for (int i = 0; i < in_list_length; ++i) {
const char* in = in_list[i];
if (should_keep_func(in, cookie)) {
*out_list_length += 1;
*out_list = realloc(*out_list, sizeof(const char*) * (*out_list_length));
(*out_list)[(*out_list_length) - 1] = string_duplicate(in);
}
}
}