diff options
Diffstat (limited to 'string-list.c')
| -rw-r--r-- | string-list.c | 168 |
1 files changed, 102 insertions, 66 deletions
diff --git a/string-list.c b/string-list.c index bf061fec56..343cf1ca90 100644 --- a/string-list.c +++ b/string-list.c @@ -1,5 +1,3 @@ -#define DISABLE_SIGN_COMPARE_WARNINGS - #include "git-compat-util.h" #include "string-list.h" @@ -17,19 +15,19 @@ 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, + int *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; return middle; @@ -40,14 +38,13 @@ static int get_entry_index(const struct string_list *list, const char *string, 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); + 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) @@ -63,10 +60,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; } @@ -116,9 +110,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); @@ -134,8 +128,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; @@ -144,8 +138,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 { @@ -171,13 +165,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); @@ -189,13 +182,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); @@ -284,55 +276,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); } |
