trailer: use list.h for doubly-linked list

Replace the existing handwritten implementation of a doubly-linked list in trailer.c with the functions and macros from list.h. This significantly simplifies the code. Signed-off-by: Jonathan Tan <jonathantanmy@google.com> Signed-off-by: Ramsay Jones <ramsay@ramsayjones.plus.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Jonathan Tan committed Oct 20, 2016 at 14:39 UTC 8966a39483fb2e823055b1c7f1a2ff9394d727e4
1 file changed +91 -167
trailer.c
+91 -167
@@ -4,6 +4,7 @@
4 #include "commit.h"
5 #include "tempfile.h"
6 #include "trailer.h"
7 +#include "list.h"
8 /*
9 * Copyright (c) 2013, 2014 Christian Couder <chriscool@tuxfamily.org>
10 */
@@ -25,19 +26,24 @@ struct conf_info {
26 static struct conf_info default_conf_info;
27
28 struct trailer_item {
28 - struct trailer_item *previous;
29 - struct trailer_item *next;
29 + struct list_head list;
30 char *token;
31 char *value;
32 struct conf_info conf;
33 };
34
35 -static struct trailer_item *first_conf_item;
35 +static LIST_HEAD(conf_head);
36
37 static char *separators = ":";
38
39 #define TRAILER_ARG_STRING "$ARG"
40
41 +/* Iterate over the elements of the list. */
42 +#define list_for_each_dir(pos, head, is_reverse) \
43 + for (pos = is_reverse ? (head)->prev : (head)->next; \
44 + pos != (head); \
45 + pos = is_reverse ? pos->prev : pos->next)
46 +
47 static int after_or_end(enum action_where where)
48 {
49 return (where == WHERE_AFTER) || (where == WHERE_END);
@@ -120,101 +126,49 @@ static void print_tok_val(FILE *outfile, const char *tok, const char *val)
126 fprintf(outfile, "%s%c %s\n", tok, separators[0], val);
127 }
128
123 -static void print_all(FILE *outfile, struct trailer_item *first, int trim_empty)
129 +static void print_all(FILE *outfile, struct list_head *head, int trim_empty)
130 {
131 + struct list_head *pos;
132 struct trailer_item *item;
126 - for (item = first; item; item = item->next) {
133 + list_for_each(pos, head) {
134 + item = list_entry(pos, struct trailer_item, list);
135 if (!trim_empty || strlen(item->value) > 0)
136 print_tok_val(outfile, item->token, item->value);
137 }
138 }
139
132 -static void update_last(struct trailer_item **last)
133 -{
134 - if (*last)
135 - while ((*last)->next != NULL)
136 - *last = (*last)->next;
137 -}
138 -
139 -static void update_first(struct trailer_item **first)
140 -{
141 - if (*first)
142 - while ((*first)->previous != NULL)
143 - *first = (*first)->previous;
144 -}
145 -
140 static void add_arg_to_input_list(struct trailer_item *on_tok,
147 - struct trailer_item *arg_tok,
148 - struct trailer_item **first,
149 - struct trailer_item **last)
150 -{
151 - if (after_or_end(arg_tok->conf.where)) {
152 - arg_tok->next = on_tok->next;
153 - on_tok->next = arg_tok;
154 - arg_tok->previous = on_tok;
155 - if (arg_tok->next)
156 - arg_tok->next->previous = arg_tok;
157 - update_last(last);
158 - } else {
159 - arg_tok->previous = on_tok->previous;
160 - on_tok->previous = arg_tok;
161 - arg_tok->next = on_tok;
162 - if (arg_tok->previous)
163 - arg_tok->previous->next = arg_tok;
164 - update_first(first);
165 - }
141 + struct trailer_item *arg_tok)
142 +{
143 + if (after_or_end(arg_tok->conf.where))
144 + list_add(&arg_tok->list, &on_tok->list);
145 + else
146 + list_add_tail(&arg_tok->list, &on_tok->list);
147 }
148
149 static int check_if_different(struct trailer_item *in_tok,
150 struct trailer_item *arg_tok,
170 - int check_all)
151 + int check_all,
152 + struct list_head *head)
153 {
154 enum action_where where = arg_tok->conf.where;
155 + struct list_head *next_head;
156 do {
174 - if (!in_tok)
175 - return 1;
157 if (same_trailer(in_tok, arg_tok))
158 return 0;
159 /*
160 * if we want to add a trailer after another one,
161 * we have to check those before this one
162 */
182 - in_tok = after_or_end(where) ? in_tok->previous : in_tok->next;
163 + next_head = after_or_end(where) ? in_tok->list.prev
164 + : in_tok->list.next;
165 + if (next_head == head)
166 + break;
167 + in_tok = list_entry(next_head, struct trailer_item, list);
168 } while (check_all);
169 return 1;
170 }
171
187 -static void remove_from_list(struct trailer_item *item,
188 - struct trailer_item **first,
189 - struct trailer_item **last)
190 -{
191 - struct trailer_item *next = item->next;
192 - struct trailer_item *previous = item->previous;
193 -
194 - if (next) {
195 - item->next->previous = previous;
196 - item->next = NULL;
197 - } else if (last)
198 - *last = previous;
199 -
200 - if (previous) {
201 - item->previous->next = next;
202 - item->previous = NULL;
203 - } else if (first)
204 - *first = next;
205 -}
206 -
207 -static struct trailer_item *remove_first(struct trailer_item **first)
208 -{
209 - struct trailer_item *item = *first;
210 - *first = item->next;
211 - if (item->next) {
212 - item->next->previous = NULL;
213 - item->next = NULL;
214 - }
215 - return item;
216 -}
217 -
172 static char *apply_command(const char *command, const char *arg)
173 {
174 struct strbuf cmd = STRBUF_INIT;
@@ -266,8 +220,7 @@ static void apply_item_command(struct trailer_item *in_tok, struct trailer_item
220 static void apply_arg_if_exists(struct trailer_item *in_tok,
221 struct trailer_item *arg_tok,
222 struct trailer_item *on_tok,
269 - struct trailer_item **in_tok_first,
270 - struct trailer_item **in_tok_last)
223 + struct list_head *head)
224 {
225 switch (arg_tok->conf.if_exists) {
226 case EXISTS_DO_NOTHING:
@@ -275,40 +228,34 @@ static void apply_arg_if_exists(struct trailer_item *in_tok,
228 break;
229 case EXISTS_REPLACE:
230 apply_item_command(in_tok, arg_tok);
278 - add_arg_to_input_list(on_tok, arg_tok,
279 - in_tok_first, in_tok_last);
280 - remove_from_list(in_tok, in_tok_first, in_tok_last);
231 + add_arg_to_input_list(on_tok, arg_tok);
232 + list_del(&in_tok->list);
233 free_trailer_item(in_tok);
234 break;
235 case EXISTS_ADD:
236 apply_item_command(in_tok, arg_tok);
285 - add_arg_to_input_list(on_tok, arg_tok,
286 - in_tok_first, in_tok_last);
237 + add_arg_to_input_list(on_tok, arg_tok);
238 break;
239 case EXISTS_ADD_IF_DIFFERENT:
240 apply_item_command(in_tok, arg_tok);
290 - if (check_if_different(in_tok, arg_tok, 1))
291 - add_arg_to_input_list(on_tok, arg_tok,
292 - in_tok_first, in_tok_last);
241 + if (check_if_different(in_tok, arg_tok, 1, head))
242 + add_arg_to_input_list(on_tok, arg_tok);
243 else
244 free_trailer_item(arg_tok);
245 break;
246 case EXISTS_ADD_IF_DIFFERENT_NEIGHBOR:
247 apply_item_command(in_tok, arg_tok);
298 - if (check_if_different(on_tok, arg_tok, 0))
299 - add_arg_to_input_list(on_tok, arg_tok,
300 - in_tok_first, in_tok_last);
248 + if (check_if_different(on_tok, arg_tok, 0, head))
249 + add_arg_to_input_list(on_tok, arg_tok);
250 else
251 free_trailer_item(arg_tok);
252 break;
253 }
254 }
255
307 -static void apply_arg_if_missing(struct trailer_item **in_tok_first,
308 - struct trailer_item **in_tok_last,
256 +static void apply_arg_if_missing(struct list_head *head,
257 struct trailer_item *arg_tok)
258 {
311 - struct trailer_item **in_tok;
259 enum action_where where;
260
261 switch (arg_tok->conf.if_missing) {
@@ -317,68 +264,60 @@ static void apply_arg_if_missing(struct trailer_item **in_tok_first,
264 break;
265 case MISSING_ADD:
266 where = arg_tok->conf.where;
320 - in_tok = after_or_end(where) ? in_tok_last : in_tok_first;
267 apply_item_command(NULL, arg_tok);
322 - if (*in_tok) {
323 - add_arg_to_input_list(*in_tok, arg_tok,
324 - in_tok_first, in_tok_last);
325 - } else {
326 - *in_tok_first = arg_tok;
327 - *in_tok_last = arg_tok;
328 - }
329 - break;
268 + if (after_or_end(where))
269 + list_add_tail(&arg_tok->list, head);
270 + else
271 + list_add(&arg_tok->list, head);
272 }
273 }
274
333 -static int find_same_and_apply_arg(struct trailer_item **in_tok_first,
334 - struct trailer_item **in_tok_last,
275 +static int find_same_and_apply_arg(struct list_head *head,
276 struct trailer_item *arg_tok)
277 {
278 + struct list_head *pos;
279 struct trailer_item *in_tok;
280 struct trailer_item *on_tok;
339 - struct trailer_item *following_tok;
281
282 enum action_where where = arg_tok->conf.where;
283 int middle = (where == WHERE_AFTER) || (where == WHERE_BEFORE);
284 int backwards = after_or_end(where);
344 - struct trailer_item *start_tok = backwards ? *in_tok_last : *in_tok_first;
285 + struct trailer_item *start_tok;
286
346 - for (in_tok = start_tok; in_tok; in_tok = following_tok) {
347 - following_tok = backwards ? in_tok->previous : in_tok->next;
287 + if (list_empty(head))
288 + return 0;
289 +
290 + start_tok = list_entry(backwards ? head->prev : head->next,
291 + struct trailer_item,
292 + list);
293 +
294 + list_for_each_dir(pos, head, backwards) {
295 + in_tok = list_entry(pos, struct trailer_item, list);
296 if (!same_token(in_tok, arg_tok))
297 continue;
298 on_tok = middle ? in_tok : start_tok;
351 - apply_arg_if_exists(in_tok, arg_tok, on_tok,
352 - in_tok_first, in_tok_last);
299 + apply_arg_if_exists(in_tok, arg_tok, on_tok, head);
300 return 1;
301 }
302 return 0;
303 }
304
358 -static void process_trailers_lists(struct trailer_item **in_tok_first,
359 - struct trailer_item **in_tok_last,
360 - struct trailer_item **arg_tok_first)
305 +static void process_trailers_lists(struct list_head *head,
306 + struct list_head *arg_head)
307 {
308 + struct list_head *pos, *p;
309 struct trailer_item *arg_tok;
363 - struct trailer_item *next_arg;
364 -
365 - if (!*arg_tok_first)
366 - return;
310
368 - for (arg_tok = *arg_tok_first; arg_tok; arg_tok = next_arg) {
311 + list_for_each_safe(pos, p, arg_head) {
312 int applied = 0;
313 + arg_tok = list_entry(pos, struct trailer_item, list);
314
371 - next_arg = arg_tok->next;
372 - remove_from_list(arg_tok, arg_tok_first, NULL);
315 + list_del(pos);
316
374 - applied = find_same_and_apply_arg(in_tok_first,
375 - in_tok_last,
376 - arg_tok);
317 + applied = find_same_and_apply_arg(head, arg_tok);
318
319 if (!applied)
379 - apply_arg_if_missing(in_tok_first,
380 - in_tok_last,
381 - arg_tok);
320 + apply_arg_if_missing(head, arg_tok);
321 }
322 }
323
@@ -438,13 +377,12 @@ static void duplicate_conf(struct conf_info *dst, const struct conf_info *src)
377
378 static struct trailer_item *get_conf_item(const char *name)
379 {
380 + struct list_head *pos;
381 struct trailer_item *item;
442 - struct trailer_item *previous;
382
383 /* Look up item with same name */
445 - for (previous = NULL, item = first_conf_item;
446 - item;
447 - previous = item, item = item->next) {
384 + list_for_each(pos, &conf_head) {
385 + item = list_entry(pos, struct trailer_item, list);
386 if (!strcasecmp(item->conf.name, name))
387 return item;
388 }
@@ -454,12 +392,7 @@ static struct trailer_item *get_conf_item(const char *name)
392 duplicate_conf(&item->conf, &default_conf_info);
393 item->conf.name = xstrdup(name);
394
457 - if (!previous)
458 - first_conf_item = item;
459 - else {
460 - previous->next = item;
461 - item->previous = previous;
462 - }
395 + list_add_tail(&item->list, &conf_head);
396
397 return item;
398 }
@@ -633,6 +566,7 @@ static struct trailer_item *create_trailer_item(const char *string)
566 struct strbuf val = STRBUF_INIT;
567 struct trailer_item *item;
568 int tok_len;
569 + struct list_head *pos;
570
571 if (parse_trailer(&tok, &val, string))
572 return NULL;
@@ -640,7 +574,8 @@ static struct trailer_item *create_trailer_item(const char *string)
574 tok_len = token_len_without_separator(tok.buf, tok.len);
575
576 /* Lookup if the token matches something in the config */
643 - for (item = first_conf_item; item; item = item->next) {
577 + list_for_each(pos, &conf_head) {
578 + item = list_entry(pos, struct trailer_item, list);
579 if (token_matches_item(tok.buf, item, tok_len))
580 return new_trailer_item(item,
581 strbuf_detach(&tok, NULL),
@@ -652,44 +587,34 @@ static struct trailer_item *create_trailer_item(const char *string)
587 strbuf_detach(&val, NULL));
588 }
589
655 -static void add_trailer_item(struct trailer_item **first,
656 - struct trailer_item **last,
657 - struct trailer_item *new)
590 +static void add_trailer_item(struct list_head *head, struct trailer_item *new)
591 {
592 if (!new)
593 return;
661 - if (!*last) {
662 - *first = new;
663 - *last = new;
664 - } else {
665 - (*last)->next = new;
666 - new->previous = *last;
667 - *last = new;
668 - }
594 + list_add_tail(&new->list, head);
595 }
596
671 -static struct trailer_item *process_command_line_args(struct string_list *trailers)
597 +static void process_command_line_args(struct list_head *arg_head,
598 + struct string_list *trailers)
599 {
673 - struct trailer_item *arg_tok_first = NULL;
674 - struct trailer_item *arg_tok_last = NULL;
600 struct string_list_item *tr;
601 struct trailer_item *item;
602 + struct list_head *pos;
603
604 /* Add a trailer item for each configured trailer with a command */
679 - for (item = first_conf_item; item; item = item->next) {
605 + list_for_each(pos, &conf_head) {
606 + item = list_entry(pos, struct trailer_item, list);
607 if (item->conf.command) {
608 struct trailer_item *new = new_trailer_item(item, NULL, NULL);
682 - add_trailer_item(&arg_tok_first, &arg_tok_last, new);
609 + add_trailer_item(arg_head, new);
610 }
611 }
612
613 /* Add a trailer item for each trailer on the command line */
614 for_each_string_list_item(tr, trailers) {
615 struct trailer_item *new = create_trailer_item(tr->string);
689 - add_trailer_item(&arg_tok_first, &arg_tok_last, new);
616 + add_trailer_item(arg_head, new);
617 }
691 -
692 - return arg_tok_first;
618 }
619
620 static struct strbuf **read_input_file(const char *file)
@@ -805,8 +730,7 @@ static void print_lines(FILE *outfile, struct strbuf **lines, int start, int end
730
731 static int process_input_file(FILE *outfile,
732 struct strbuf **lines,
808 - struct trailer_item **in_tok_first,
809 - struct trailer_item **in_tok_last)
733 + struct list_head *head)
734 {
735 int count = 0;
736 int patch_start, trailer_start, trailer_end, i;
@@ -829,18 +753,19 @@ static int process_input_file(FILE *outfile,
753 for (i = trailer_start; i < trailer_end; i++) {
754 if (lines[i]->buf[0] != comment_line_char) {
755 struct trailer_item *new = create_trailer_item(lines[i]->buf);
832 - add_trailer_item(in_tok_first, in_tok_last, new);
756 + add_trailer_item(head, new);
757 }
758 }
759
760 return trailer_end;
761 }
762
839 -static void free_all(struct trailer_item **first)
763 +static void free_all(struct list_head *head)
764 {
841 - while (*first) {
842 - struct trailer_item *item = remove_first(first);
843 - free_trailer_item(item);
765 + struct list_head *pos, *p;
766 + list_for_each_safe(pos, p, head) {
767 + list_del(pos);
768 + free_trailer_item(list_entry(pos, struct trailer_item, list));
769 }
770 }
771
@@ -877,9 +802,8 @@ static FILE *create_in_place_tempfile(const char *file)
802
803 void process_trailers(const char *file, int in_place, int trim_empty, struct string_list *trailers)
804 {
880 - struct trailer_item *in_tok_first = NULL;
881 - struct trailer_item *in_tok_last = NULL;
882 - struct trailer_item *arg_tok_first;
805 + LIST_HEAD(head);
806 + LIST_HEAD(arg_head);
807 struct strbuf **lines;
808 int trailer_end;
809 FILE *outfile = stdout;
@@ -894,15 +818,15 @@ void process_trailers(const char *file, int in_place, int trim_empty, struct str
818 outfile = create_in_place_tempfile(file);
819
820 /* Print the lines before the trailers */
897 - trailer_end = process_input_file(outfile, lines, &in_tok_first, &in_tok_last);
821 + trailer_end = process_input_file(outfile, lines, &head);
822
899 - arg_tok_first = process_command_line_args(trailers);
823 + process_command_line_args(&arg_head, trailers);
824
901 - process_trailers_lists(&in_tok_first, &in_tok_last, &arg_tok_first);
825 + process_trailers_lists(&head, &arg_head);
826
903 - print_all(outfile, in_tok_first, trim_empty);
827 + print_all(outfile, &head, trim_empty);
828
905 - free_all(&in_tok_first);
829 + free_all(&head);
830
831 /* Print the lines after the trailers as is */
832 print_lines(outfile, lines, trailer_end, INT_MAX);