summaryrefslogtreecommitdiff
path: root/string-list.c
diff options
context:
space:
mode:
Diffstat (limited to 'string-list.c')
-rw-r--r--string-list.c193
1 files changed, 115 insertions, 78 deletions
diff --git a/string-list.c b/string-list.c
index 954569f381..08dc00984c 100644
--- a/string-list.c
+++ b/string-list.c
@@ -15,37 +15,38 @@ void string_list_init_dup(struct string_list *list)
/* 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)
+static size_t get_entry_index(const struct string_list *list, const char *string,
+ bool *exact_match)
{
- int left = -1, right = list->nr;
+ size_t left = 0, right = list->nr;
compare_strings_fn cmp = list->cmp ? list->cmp : strcmp;
- while (left + 1 < right) {
- int middle = left + (right - left) / 2;
+ while (left < right) {
+ size_t middle = left + (right - left) / 2;
int compare = cmp(string, list->items[middle].string);
if (compare < 0)
right = middle;
else if (compare > 0)
- left = middle;
+ left = middle + 1;
else {
- *exact_match = 1;
+ if (exact_match)
+ *exact_match = true;
return middle;
}
}
- *exact_match = 0;
+ if (exact_match)
+ *exact_match = false;
return right;
}
-/* returns -1-index if already exists */
-static int add_entry(int insert_at, struct string_list *list, const char *string)
+static size_t add_entry(struct string_list *list, const char *string)
{
- int exact_match = 0;
- int index = insert_at != -1 ? insert_at : get_entry_index(list, string, &exact_match);
+ bool exact_match;
+ size_t index = get_entry_index(list, string, &exact_match);
if (exact_match)
- return -1 - index;
+ return index;
ALLOC_GROW(list->items, list->nr+1, list->alloc);
if (index < list->nr)
@@ -61,10 +62,7 @@ static int add_entry(int insert_at, struct string_list *list, const char *string
struct string_list_item *string_list_insert(struct string_list *list, const char *string)
{
- int index = add_entry(-1, list, string);
-
- if (index < 0)
- index = -1 - index;
+ size_t index = add_entry(list, string);
return list->items + index;
}
@@ -72,7 +70,7 @@ struct string_list_item *string_list_insert(struct string_list *list, const char
void string_list_remove(struct string_list *list, const char *string,
int free_util)
{
- int exact_match;
+ bool exact_match;
int i = get_entry_index(list, string, &exact_match);
if (exact_match) {
@@ -86,26 +84,23 @@ void string_list_remove(struct string_list *list, const char *string,
}
}
-int string_list_has_string(const struct string_list *list, const char *string)
+bool string_list_has_string(const struct string_list *list, const char *string)
{
- int exact_match;
+ bool exact_match;
get_entry_index(list, string, &exact_match);
return exact_match;
}
-int string_list_find_insert_index(const struct string_list *list, const char *string,
- int negative_existing_index)
+size_t string_list_find_insert_index(const struct string_list *list, const char *string,
+ bool *exact_match)
{
- int exact_match;
- int index = get_entry_index(list, string, &exact_match);
- if (exact_match)
- index = -1 - (negative_existing_index ? index : 0);
- return index;
+ return get_entry_index(list, string, exact_match);
}
struct string_list_item *string_list_lookup(struct string_list *list, const char *string)
{
- int exact_match, i = get_entry_index(list, string, &exact_match);
+ bool exact_match;
+ size_t i = get_entry_index(list, string, &exact_match);
if (!exact_match)
return NULL;
return list->items + i;
@@ -114,9 +109,9 @@ struct string_list_item *string_list_lookup(struct string_list *list, const char
void string_list_remove_duplicates(struct string_list *list, int free_util)
{
if (list->nr > 1) {
- int src, dst;
+ size_t dst = 1;
compare_strings_fn cmp = list->cmp ? list->cmp : strcmp;
- for (src = dst = 1; src < list->nr; src++) {
+ for (size_t src = 1; src < list->nr; src++) {
if (!cmp(list->items[dst - 1].string, list->items[src].string)) {
if (list->strdup_strings)
free(list->items[src].string);
@@ -132,8 +127,8 @@ void string_list_remove_duplicates(struct string_list *list, int free_util)
int for_each_string_list(struct string_list *list,
string_list_each_func_t fn, void *cb_data)
{
- int i, ret = 0;
- for (i = 0; i < list->nr; i++)
+ int ret = 0;
+ for (size_t i = 0; i < list->nr; i++)
if ((ret = fn(&list->items[i], cb_data)))
break;
return ret;
@@ -142,8 +137,8 @@ int for_each_string_list(struct string_list *list,
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++) {
+ size_t dst = 0;
+ for (size_t src = 0; src < list->nr; src++) {
if (want(&list->items[src], cb_data)) {
list->items[dst++] = list->items[src];
} else {
@@ -169,13 +164,12 @@ void string_list_remove_empty_items(struct string_list *list, int free_util)
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++)
+ for (size_t i = 0; i < list->nr; i++)
free(list->items[i].string);
}
if (free_util) {
- for (i = 0; i < list->nr; i++)
+ for (size_t i = 0; i < list->nr; i++)
free(list->items[i].util);
}
free(list->items);
@@ -187,13 +181,12 @@ void string_list_clear(struct string_list *list, int free_util)
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++)
+ for (size_t 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++)
+ for (size_t i = 0; i < list->nr; i++)
free(list->items[i].string);
}
free(list->items);
@@ -282,55 +275,99 @@ void unsorted_string_list_delete_item(struct string_list *list, int i, int free_
list->nr--;
}
-int string_list_split(struct string_list *list, const char *string,
- int delim, int maxsplit)
+/*
+ * append a substring [p..end] to list; return number of things it
+ * appended to the list.
+ */
+static int append_one(struct string_list *list,
+ const char *p, const char *end,
+ int in_place, unsigned flags)
+{
+ if (!end)
+ end = p + strlen(p);
+
+ if ((flags & STRING_LIST_SPLIT_TRIM)) {
+ /* rtrim */
+ for (; p < end; end--)
+ if (!isspace(end[-1]))
+ break;
+ }
+
+ if ((flags & STRING_LIST_SPLIT_NONEMPTY) && (end <= p))
+ return 0;
+
+ if (in_place) {
+ *((char *)end) = '\0';
+ string_list_append(list, p);
+ } else {
+ string_list_append_nodup(list, xmemdupz(p, end - p));
+ }
+ return 1;
+}
+
+/*
+ * Unfortunately this cannot become a public interface, as _in_place()
+ * wants to have "const char *string" while the other variant wants to
+ * have "char *string" for type safety.
+ *
+ * This accepts "const char *string" to allow both wrappers to use it;
+ * it internally casts away the constness when in_place is true by
+ * taking advantage of strpbrk() that takes a "const char *" arg and
+ * returns "char *" pointer into that const string. Yucky but works ;-).
+ */
+static int split_string(struct string_list *list, const char *string, const char *delim,
+ int maxsplit, int in_place, unsigned flags)
{
int count = 0;
- const char *p = string, *end;
+ const char *p = string;
+
+ if (in_place && list->strdup_strings)
+ BUG("string_list_split_in_place() called with strdup_strings");
+ else if (!in_place && !list->strdup_strings)
+ BUG("string_list_split() called without strdup_strings");
- 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;
+ char *end;
+
+ if (flags & STRING_LIST_SPLIT_TRIM) {
+ /* ltrim */
+ while (*p && isspace(*p))
+ p++;
}
- end = strchr(p, delim);
- if (end) {
- string_list_append_nodup(list, xmemdupz(p, end - p));
- p = end + 1;
- } else {
- string_list_append(list, p);
+
+ if (0 <= maxsplit && maxsplit <= count)
+ end = NULL;
+ else
+ end = strpbrk(p, delim);
+
+ count += append_one(list, p, end, in_place, flags);
+
+ if (!end)
return count;
- }
+ p = end + 1;
}
}
+int string_list_split(struct string_list *list, const char *string,
+ const char *delim, int maxsplit)
+{
+ return split_string(list, string, delim, maxsplit, 0, 0);
+}
+
int string_list_split_in_place(struct string_list *list, char *string,
const char *delim, int maxsplit)
{
- int count = 0;
- char *p = string, *end;
+ return split_string(list, string, delim, maxsplit, 1, 0);
+}
- 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 = strpbrk(p, delim);
- if (end) {
- *end = '\0';
- string_list_append(list, p);
- p = end + 1;
- } else {
- string_list_append(list, p);
- return count;
- }
- }
+int string_list_split_f(struct string_list *list, const char *string,
+ const char *delim, int maxsplit, unsigned flags)
+{
+ return split_string(list, string, delim, maxsplit, 0, flags);
+}
+
+int string_list_split_in_place_f(struct string_list *list, char *string,
+ const char *delim, int maxsplit, unsigned flags)
+{
+ return split_string(list, string, delim, maxsplit, 1, flags);
}