string-list.c 7.5 KB
Newer Older
1 2 3
#include "cache.h"
#include "string-list.h"

4 5 6 7 8 9
void string_list_init(struct string_list *list, int strdup_strings)
{
	memset(list, 0, sizeof(*list));
	list->strdup_strings = strdup_strings;
}

10 11 12 13 14 15
/* if there is no exact match, point to the index where the entry could be
 * inserted */
static int get_entry_index(const struct string_list *list, const char *string,
		int *exact_match)
{
	int left = -1, right = list->nr;
16
	compare_strings_fn cmp = list->cmp ? list->cmp : strcmp;
17 18 19

	while (left + 1 < right) {
		int middle = (left + right) / 2;
20
		int compare = cmp(string, list->items[middle].string);
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
		if (compare < 0)
			right = middle;
		else if (compare > 0)
			left = middle;
		else {
			*exact_match = 1;
			return middle;
		}
	}

	*exact_match = 0;
	return right;
}

/* returns -1-index if already exists */
36
static int add_entry(int insert_at, struct string_list *list, const char *string)
37
{
38 39
	int exact_match = 0;
	int index = insert_at != -1 ? insert_at : get_entry_index(list, string, &exact_match);
40 41 42 43 44 45

	if (exact_match)
		return -1 - index;

	if (list->nr + 1 >= list->alloc) {
		list->alloc += 32;
46
		REALLOC_ARRAY(list->items, list->alloc);
47 48 49 50 51 52 53 54 55 56 57 58 59
	}
	if (index < list->nr)
		memmove(list->items + index + 1, list->items + index,
				(list->nr - index)
				* sizeof(struct string_list_item));
	list->items[index].string = list->strdup_strings ?
		xstrdup(string) : (char *)string;
	list->items[index].util = NULL;
	list->nr++;

	return index;
}

60
struct string_list_item *string_list_insert(struct string_list *list, const char *string)
61
{
62
	return string_list_insert_at_index(list, -1, string);
63 64
}

65 66
struct string_list_item *string_list_insert_at_index(struct string_list *list,
						     int insert_at, const char *string)
67 68
{
	int index = add_entry(insert_at, list, string);
69 70 71 72 73 74 75 76 77 78 79 80 81 82

	if (index < 0)
		index = -1 - index;

	return list->items + index;
}

int string_list_has_string(const struct string_list *list, const char *string)
{
	int exact_match;
	get_entry_index(list, string, &exact_match);
	return exact_match;
}

83 84 85 86 87 88 89 90 91 92
int string_list_find_insert_index(const struct string_list *list, const char *string,
				  int negative_existing_index)
{
	int exact_match;
	int index = get_entry_index(list, string, &exact_match);
	if (exact_match)
		index = -1 - (negative_existing_index ? index : 0);
	return index;
}

93
struct string_list_item *string_list_lookup(struct string_list *list, const char *string)
94 95 96 97 98 99 100
{
	int exact_match, i = get_entry_index(list, string, &exact_match);
	if (!exact_match)
		return NULL;
	return list->items + i;
}

101 102 103 104
void string_list_remove_duplicates(struct string_list *list, int free_util)
{
	if (list->nr > 1) {
		int src, dst;
105
		compare_strings_fn cmp = list->cmp ? list->cmp : strcmp;
106
		for (src = dst = 1; src < list->nr; src++) {
107
			if (!cmp(list->items[dst - 1].string, list->items[src].string)) {
108 109 110 111 112 113 114 115 116 117 118
				if (list->strdup_strings)
					free(list->items[src].string);
				if (free_util)
					free(list->items[src].util);
			} else
				list->items[dst++] = list->items[src];
		}
		list->nr = dst;
	}
}

119 120
int for_each_string_list(struct string_list *list,
			 string_list_each_func_t fn, void *cb_data)
121 122 123 124 125 126 127 128
{
	int i, ret = 0;
	for (i = 0; i < list->nr; i++)
		if ((ret = fn(&list->items[i], cb_data)))
			break;
	return ret;
}

129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
void filter_string_list(struct string_list *list, int free_util,
			string_list_each_func_t want, void *cb_data)
{
	int src, dst = 0;
	for (src = 0; src < list->nr; src++) {
		if (want(&list->items[src], cb_data)) {
			list->items[dst++] = list->items[src];
		} else {
			if (list->strdup_strings)
				free(list->items[src].string);
			if (free_util)
				free(list->items[src].util);
		}
	}
	list->nr = dst;
}

146 147 148 149 150 151 152 153 154
static int item_is_not_empty(struct string_list_item *item, void *unused)
{
	return *item->string != '\0';
}

void string_list_remove_empty_items(struct string_list *list, int free_util) {
	filter_string_list(list, free_util, item_is_not_empty, NULL);
}

155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
void string_list_clear(struct string_list *list, int free_util)
{
	if (list->items) {
		int i;
		if (list->strdup_strings) {
			for (i = 0; i < list->nr; i++)
				free(list->items[i].string);
		}
		if (free_util) {
			for (i = 0; i < list->nr; i++)
				free(list->items[i].util);
		}
		free(list->items);
	}
	list->items = NULL;
	list->nr = list->alloc = 0;
}

173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191
void string_list_clear_func(struct string_list *list, string_list_clear_func_t clearfunc)
{
	if (list->items) {
		int i;
		if (clearfunc) {
			for (i = 0; i < list->nr; i++)
				clearfunc(list->items[i].util, list->items[i].string);
		}
		if (list->strdup_strings) {
			for (i = 0; i < list->nr; i++)
				free(list->items[i].string);
		}
		free(list->items);
	}
	list->items = NULL;
	list->nr = list->alloc = 0;
}


192
void print_string_list(const struct string_list *p, const char *text)
193 194 195 196 197 198 199 200
{
	int i;
	if ( text )
		printf("%s\n", text);
	for (i = 0; i < p->nr; i++)
		printf("%s:%p\n", p->items[i].string, p->items[i].util);
}

201 202
struct string_list_item *string_list_append_nodup(struct string_list *list,
						  char *string)
203
{
204
	struct string_list_item *retval;
205
	ALLOC_GROW(list->items, list->nr + 1, list->alloc);
206 207 208 209 210 211 212 213 214 215 216 217
	retval = &list->items[list->nr++];
	retval->string = string;
	retval->util = NULL;
	return retval;
}

struct string_list_item *string_list_append(struct string_list *list,
					    const char *string)
{
	return string_list_append_nodup(
			list,
			list->strdup_strings ? xstrdup(string) : (char *)string);
218 219
}

220 221 222 223
/* Yuck */
static compare_strings_fn compare_for_qsort;

/* Only call this from inside sort_string_list! */
224 225 226 227
static int cmp_items(const void *a, const void *b)
{
	const struct string_list_item *one = a;
	const struct string_list_item *two = b;
228
	return compare_for_qsort(one->string, two->string);
229 230 231 232
}

void sort_string_list(struct string_list *list)
{
233
	compare_for_qsort = list->cmp ? list->cmp : strcmp;
234 235 236
	qsort(list->items, list->nr, sizeof(*list->items), cmp_items);
}

237 238
struct string_list_item *unsorted_string_list_lookup(struct string_list *list,
						     const char *string)
239 240
{
	int i;
241 242
	compare_strings_fn cmp = list->cmp ? list->cmp : strcmp;

243
	for (i = 0; i < list->nr; i++)
244
		if (!cmp(string, list->items[i].string))
245 246 247 248 249 250 251 252
			return list->items + i;
	return NULL;
}

int unsorted_string_list_has_string(struct string_list *list,
				    const char *string)
{
	return unsorted_string_list_lookup(list, string) != NULL;
253 254
}

255 256 257 258 259 260 261 262 263
void unsorted_string_list_delete_item(struct string_list *list, int i, int free_util)
{
	if (list->strdup_strings)
		free(list->items[i].string);
	if (free_util)
		free(list->items[i].util);
	list->items[i] = list->items[list->nr-1];
	list->nr--;
}
264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316

int string_list_split(struct string_list *list, const char *string,
		      int delim, int maxsplit)
{
	int count = 0;
	const char *p = string, *end;

	if (!list->strdup_strings)
		die("internal error in string_list_split(): "
		    "list->strdup_strings must be set");
	for (;;) {
		count++;
		if (maxsplit >= 0 && count > maxsplit) {
			string_list_append(list, p);
			return count;
		}
		end = strchr(p, delim);
		if (end) {
			string_list_append_nodup(list, xmemdupz(p, end - p));
			p = end + 1;
		} else {
			string_list_append(list, p);
			return count;
		}
	}
}

int string_list_split_in_place(struct string_list *list, char *string,
			       int delim, int maxsplit)
{
	int count = 0;
	char *p = string, *end;

	if (list->strdup_strings)
		die("internal error in string_list_split_in_place(): "
		    "list->strdup_strings must not be set");
	for (;;) {
		count++;
		if (maxsplit >= 0 && count > maxsplit) {
			string_list_append(list, p);
			return count;
		}
		end = strchr(p, delim);
		if (end) {
			*end = '\0';
			string_list_append(list, p);
			p = end + 1;
		} else {
			string_list_append(list, p);
			return count;
		}
	}
}