The sixteenth batch
[git/gitster.git] / string-list.c
blob53faaa84207bf90901a26ccc89217c44191ec352
1 #include "git-compat-util.h"
2 #include "string-list.h"
4 void string_list_init_nodup(struct string_list *list)
6 struct string_list blank = STRING_LIST_INIT_NODUP;
7 memcpy(list, &blank, sizeof(*list));
10 void string_list_init_dup(struct string_list *list)
12 struct string_list blank = STRING_LIST_INIT_DUP;
13 memcpy(list, &blank, sizeof(*list));
16 /* if there is no exact match, point to the index where the entry could be
17 * inserted */
18 static size_t get_entry_index(const struct string_list *list, const char *string,
19 int *exact_match)
21 size_t left = 0, right = list->nr;
22 compare_strings_fn cmp = list->cmp ? list->cmp : strcmp;
24 while (left < right) {
25 size_t middle = left + (right - left) / 2;
26 int compare = cmp(string, list->items[middle].string);
27 if (compare < 0)
28 right = middle;
29 else if (compare > 0)
30 left = middle + 1;
31 else {
32 *exact_match = 1;
33 return middle;
37 *exact_match = 0;
38 return right;
41 static size_t add_entry(struct string_list *list, const char *string)
43 int exact_match = 0;
44 size_t index = get_entry_index(list, string, &exact_match);
46 if (exact_match)
47 return index;
49 ALLOC_GROW(list->items, list->nr+1, list->alloc);
50 if (index < list->nr)
51 MOVE_ARRAY(list->items + index + 1, list->items + index,
52 list->nr - index);
53 list->items[index].string = list->strdup_strings ?
54 xstrdup(string) : (char *)string;
55 list->items[index].util = NULL;
56 list->nr++;
58 return index;
61 struct string_list_item *string_list_insert(struct string_list *list, const char *string)
63 size_t index = add_entry(list, string);
65 return list->items + index;
68 void string_list_remove(struct string_list *list, const char *string,
69 int free_util)
71 int exact_match;
72 int i = get_entry_index(list, string, &exact_match);
74 if (exact_match) {
75 if (list->strdup_strings)
76 free(list->items[i].string);
77 if (free_util)
78 free(list->items[i].util);
80 list->nr--;
81 MOVE_ARRAY(list->items + i, list->items + i + 1, list->nr - i);
85 int string_list_has_string(const struct string_list *list, const char *string)
87 int exact_match;
88 get_entry_index(list, string, &exact_match);
89 return exact_match;
92 int string_list_find_insert_index(const struct string_list *list, const char *string,
93 int negative_existing_index)
95 int exact_match;
96 int index = get_entry_index(list, string, &exact_match);
97 if (exact_match)
98 index = -1 - (negative_existing_index ? index : 0);
99 return index;
102 struct string_list_item *string_list_lookup(struct string_list *list, const char *string)
104 int exact_match, i = get_entry_index(list, string, &exact_match);
105 if (!exact_match)
106 return NULL;
107 return list->items + i;
110 void string_list_remove_duplicates(struct string_list *list, int free_util)
112 if (list->nr > 1) {
113 size_t dst = 1;
114 compare_strings_fn cmp = list->cmp ? list->cmp : strcmp;
115 for (size_t src = 1; src < list->nr; src++) {
116 if (!cmp(list->items[dst - 1].string, list->items[src].string)) {
117 if (list->strdup_strings)
118 free(list->items[src].string);
119 if (free_util)
120 free(list->items[src].util);
121 } else
122 list->items[dst++] = list->items[src];
124 list->nr = dst;
128 int for_each_string_list(struct string_list *list,
129 string_list_each_func_t fn, void *cb_data)
131 int ret = 0;
132 for (size_t i = 0; i < list->nr; i++)
133 if ((ret = fn(&list->items[i], cb_data)))
134 break;
135 return ret;
138 void filter_string_list(struct string_list *list, int free_util,
139 string_list_each_func_t want, void *cb_data)
141 size_t dst = 0;
142 for (size_t src = 0; src < list->nr; src++) {
143 if (want(&list->items[src], cb_data)) {
144 list->items[dst++] = list->items[src];
145 } else {
146 if (list->strdup_strings)
147 free(list->items[src].string);
148 if (free_util)
149 free(list->items[src].util);
152 list->nr = dst;
155 static int item_is_not_empty(struct string_list_item *item, void *data UNUSED)
157 return *item->string != '\0';
160 void string_list_remove_empty_items(struct string_list *list, int free_util)
162 filter_string_list(list, free_util, item_is_not_empty, NULL);
165 void string_list_clear(struct string_list *list, int free_util)
167 if (list->items) {
168 if (list->strdup_strings) {
169 for (size_t i = 0; i < list->nr; i++)
170 free(list->items[i].string);
172 if (free_util) {
173 for (size_t i = 0; i < list->nr; i++)
174 free(list->items[i].util);
176 free(list->items);
178 list->items = NULL;
179 list->nr = list->alloc = 0;
182 void string_list_clear_func(struct string_list *list, string_list_clear_func_t clearfunc)
184 if (list->items) {
185 if (clearfunc) {
186 for (size_t i = 0; i < list->nr; i++)
187 clearfunc(list->items[i].util, list->items[i].string);
189 if (list->strdup_strings) {
190 for (size_t i = 0; i < list->nr; i++)
191 free(list->items[i].string);
193 free(list->items);
195 list->items = NULL;
196 list->nr = list->alloc = 0;
199 void string_list_setlen(struct string_list *list, size_t nr)
201 if (list->strdup_strings)
202 BUG("cannot setlen a string_list which owns its entries");
203 if (nr > list->nr)
204 BUG("cannot grow a string_list with setlen");
205 list->nr = nr;
208 struct string_list_item *string_list_append_nodup(struct string_list *list,
209 char *string)
211 struct string_list_item *retval;
212 ALLOC_GROW(list->items, list->nr + 1, list->alloc);
213 retval = &list->items[list->nr++];
214 retval->string = string;
215 retval->util = NULL;
216 return retval;
219 struct string_list_item *string_list_append(struct string_list *list,
220 const char *string)
222 return string_list_append_nodup(
223 list,
224 list->strdup_strings ? xstrdup(string) : (char *)string);
228 * Encapsulate the compare function pointer because ISO C99 forbids
229 * casting from void * to a function pointer and vice versa.
231 struct string_list_sort_ctx
233 compare_strings_fn cmp;
236 static int cmp_items(const void *a, const void *b, void *ctx)
238 struct string_list_sort_ctx *sort_ctx = ctx;
239 const struct string_list_item *one = a;
240 const struct string_list_item *two = b;
241 return sort_ctx->cmp(one->string, two->string);
244 void string_list_sort(struct string_list *list)
246 struct string_list_sort_ctx sort_ctx = {list->cmp ? list->cmp : strcmp};
248 QSORT_S(list->items, list->nr, cmp_items, &sort_ctx);
251 struct string_list_item *unsorted_string_list_lookup(struct string_list *list,
252 const char *string)
254 struct string_list_item *item;
255 compare_strings_fn cmp = list->cmp ? list->cmp : strcmp;
257 for_each_string_list_item(item, list)
258 if (!cmp(string, item->string))
259 return item;
260 return NULL;
263 int unsorted_string_list_has_string(struct string_list *list,
264 const char *string)
266 return unsorted_string_list_lookup(list, string) != NULL;
269 void unsorted_string_list_delete_item(struct string_list *list, int i, int free_util)
271 if (list->strdup_strings)
272 free(list->items[i].string);
273 if (free_util)
274 free(list->items[i].util);
275 list->items[i] = list->items[list->nr-1];
276 list->nr--;
279 int string_list_split(struct string_list *list, const char *string,
280 int delim, int maxsplit)
282 int count = 0;
283 const char *p = string, *end;
285 if (!list->strdup_strings)
286 die("internal error in string_list_split(): "
287 "list->strdup_strings must be set");
288 for (;;) {
289 count++;
290 if (maxsplit >= 0 && count > maxsplit) {
291 string_list_append(list, p);
292 return count;
294 end = strchr(p, delim);
295 if (end) {
296 string_list_append_nodup(list, xmemdupz(p, end - p));
297 p = end + 1;
298 } else {
299 string_list_append(list, p);
300 return count;
305 int string_list_split_in_place(struct string_list *list, char *string,
306 const char *delim, int maxsplit)
308 int count = 0;
309 char *p = string, *end;
311 if (list->strdup_strings)
312 die("internal error in string_list_split_in_place(): "
313 "list->strdup_strings must not be set");
314 for (;;) {
315 count++;
316 if (maxsplit >= 0 && count > maxsplit) {
317 string_list_append(list, p);
318 return count;
320 end = strpbrk(p, delim);
321 if (end) {
322 *end = '\0';
323 string_list_append(list, p);
324 p = end + 1;
325 } else {
326 string_list_append(list, p);
327 return count;