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 <pbonz...@redhat.com>
---
 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


Reply via email to