Create a new function apply_arg that takes care of computing the new trailer's "neighbor", checking for duplicates through a pluggable callback, and adding the new argument according to "trailer.where". Rename after_or_end, and don't use it in apply_arg. It's a coincidence that the conditions for "scan backwards" and "add after" are the same. This simplifies find_same_and_apply_arg so that it does exactly what the name says. apply_arg_if_missing can also use the new function; before, it was redoing add_arg_to_input_list's job in a slightly different fashion. Signed-off-by: Paolo Bonzini <pbonzini@xxxxxxxxxx> --- trailer.c | 125 +++++++++++++++++++++++++++++++++++++------------------------- 1 file changed, 75 insertions(+), 50 deletions(-) diff --git a/trailer.c b/trailer.c index 91f89db7f..ce0d94074 100644 --- a/trailer.c +++ b/trailer.c @@ -58,7 +58,7 @@ static const char *git_generated_prefixes[] = { pos != (head); \ pos = is_reverse ? pos->prev : pos->next) -static int after_or_end(enum trailer_where where) +static int scan_backwards(enum trailer_where where) { return (where == WHERE_AFTER) || (where == WHERE_END); } @@ -181,18 +181,8 @@ static struct trailer_item *trailer_from_arg(struct arg_item *arg_tok) return new; } -static void add_arg_to_input_list(struct trailer_item *on_tok, - struct arg_item *arg_tok) -{ - int aoe = after_or_end(arg_tok->conf.where); - struct trailer_item *to_add = trailer_from_arg(arg_tok); - if (aoe) - list_add(&to_add->list, &on_tok->list); - else - list_add_tail(&to_add->list, &on_tok->list); -} - static int check_if_different(struct trailer_item *in_tok, + struct trailer_item *neighbor, struct arg_item *arg_tok, struct list_head *head) { @@ -203,8 +193,8 @@ static int check_if_different(struct trailer_item *in_tok, * if we want to add a trailer after another one, * we have to check those before this one */ - next_head = after_or_end(where) ? in_tok->list.prev - : in_tok->list.next; + next_head = scan_backwards(where) ? in_tok->list.prev + : in_tok->list.next; if (next_head == head) return 1; in_tok = list_entry(next_head, struct trailer_item, list); @@ -212,6 +202,14 @@ static int check_if_different(struct trailer_item *in_tok, return 0; } +static int check_if_different_neighbor(struct trailer_item *in_tok, + struct trailer_item *neighbor, + struct arg_item *arg_tok, + struct list_head *head) +{ + return !same_trailer(neighbor, arg_tok); +} + static char *apply_command(const char *command, const char *arg) { struct strbuf cmd = STRBUF_INIT; @@ -260,33 +258,80 @@ static void apply_item_command(struct trailer_item *in_tok, struct arg_item *arg } } +static int apply_arg(struct trailer_item *in_tok, + struct arg_item *arg_tok, + struct list_head *head, + int (*check)(struct trailer_item *in_tok, + struct trailer_item *neighbor, + struct arg_item *arg_tok, + struct list_head *head), + int replace) +{ + struct trailer_item *to_add, *neighbor; + struct list_head *place; + int add_after; + + enum trailer_where where = arg_tok->conf.where; + int middle = (where == WHERE_AFTER) || (where == WHERE_BEFORE); + + /* + * No other trailer to apply arg_tok one before/after. Put it + * before/after _all_ other trailers. + */ + if (!in_tok && middle) { + where = (where == WHERE_AFTER) ? WHERE_END : WHERE_START; + middle = 0; + } + + if (list_empty(head)) { + add_after = 1; + place = head; + neighbor = NULL; + } else if (middle) { + add_after = (where == WHERE_AFTER); + place = &in_tok->list; + neighbor = in_tok; + } else { + add_after = (where == WHERE_END); + place = (where == WHERE_END) ? head->prev : head->next; + neighbor = list_entry(place, struct trailer_item, list); + } + + apply_item_command(in_tok, arg_tok); + if (check && !check(in_tok, neighbor, arg_tok, head)) + return 0; + + to_add = trailer_from_arg(arg_tok); + if (add_after) + list_add(&to_add->list, place); + else + list_add_tail(&to_add->list, place); + + if (replace) { + list_del(&in_tok->list); + free_trailer_item(in_tok); + } + return 1; +} + static void apply_arg_if_exists(struct trailer_item *in_tok, struct arg_item *arg_tok, - struct trailer_item *on_tok, struct list_head *head) { switch (arg_tok->conf.if_exists) { case EXISTS_DO_NOTHING: break; case EXISTS_REPLACE: - apply_item_command(in_tok, arg_tok); - add_arg_to_input_list(on_tok, arg_tok); - list_del(&in_tok->list); - free_trailer_item(in_tok); + apply_arg(in_tok, arg_tok, head, NULL, 1); break; case EXISTS_ADD: - apply_item_command(in_tok, arg_tok); - add_arg_to_input_list(on_tok, arg_tok); + apply_arg(in_tok, arg_tok, head, NULL, 0); break; case EXISTS_ADD_IF_DIFFERENT: - apply_item_command(in_tok, arg_tok); - if (check_if_different(in_tok, arg_tok, head)) - add_arg_to_input_list(on_tok, arg_tok); + apply_arg(in_tok, arg_tok, head, check_if_different, 0); break; case EXISTS_ADD_IF_DIFFERENT_NEIGHBOR: - apply_item_command(in_tok, arg_tok); - if (!same_trailer(on_tok, arg_tok)) - add_arg_to_input_list(on_tok, arg_tok); + apply_arg(in_tok, arg_tok, head, check_if_different_neighbor, 0); break; default: die("BUG: trailer.c: unhandled value %d", @@ -297,24 +342,12 @@ static void apply_arg_if_exists(struct trailer_item *in_tok, static void apply_arg_if_missing(struct list_head *head, struct arg_item *arg_tok) { - enum trailer_where where; - struct trailer_item *to_add; - switch (arg_tok->conf.if_missing) { case MISSING_DO_NOTHING: break; case MISSING_ADD: - where = arg_tok->conf.where; - apply_item_command(NULL, arg_tok); - to_add = trailer_from_arg(arg_tok); - if (after_or_end(where)) - list_add_tail(&to_add->list, head); - else - list_add(&to_add->list, head); + apply_arg(NULL, arg_tok, head, NULL, 0); break; - default: - die("BUG: trailer.c: unhandled value %d", - arg_tok->conf.if_missing); } } @@ -323,26 +356,18 @@ static int find_same_and_apply_arg(struct list_head *head, { struct list_head *pos; struct trailer_item *in_tok; - struct trailer_item *on_tok; enum trailer_where where = arg_tok->conf.where; - int middle = (where == WHERE_AFTER) || (where == WHERE_BEFORE); - int backwards = after_or_end(where); - struct trailer_item *start_tok; + int backwards = scan_backwards(where); if (list_empty(head)) return 0; - start_tok = list_entry(backwards ? head->prev : head->next, - struct trailer_item, - list); - list_for_each_dir(pos, head, backwards) { in_tok = list_entry(pos, struct trailer_item, list); if (!same_token(in_tok, arg_tok)) continue; - on_tok = middle ? in_tok : start_tok; - apply_arg_if_exists(in_tok, arg_tok, on_tok, head); + apply_arg_if_exists(in_tok, arg_tok, head); return 1; } return 0; -- 2.14.2