Skip to content

Commit 4103818

Browse files
chriscoolgitster
authored andcommitted
trailer: process trailers from input message and arguments
Implement the logic to process trailers from the input message and from arguments. At the beginning trailers from the input message are in their own "in_tok" doubly linked list, and trailers from arguments are in their own "arg_tok" doubly linked list. The lists are traversed and when an "arg_tok" should be "applied", it is removed from its list and inserted into the "in_tok" list. Signed-off-by: Christian Couder <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 9385b5d commit 4103818

File tree

1 file changed

+210
-0
lines changed

1 file changed

+210
-0
lines changed

trailer.c

Lines changed: 210 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,3 +67,213 @@ static int same_trailer(struct trailer_item *a, struct trailer_item *b)
6767
{
6868
return same_token(a, b) && same_value(a, b);
6969
}
70+
71+
static void free_trailer_item(struct trailer_item *item)
72+
{
73+
free(item->conf.name);
74+
free(item->conf.key);
75+
free(item->conf.command);
76+
free((char *)item->token);
77+
free((char *)item->value);
78+
free(item);
79+
}
80+
81+
static void update_last(struct trailer_item **last)
82+
{
83+
if (*last)
84+
while ((*last)->next != NULL)
85+
*last = (*last)->next;
86+
}
87+
88+
static void update_first(struct trailer_item **first)
89+
{
90+
if (*first)
91+
while ((*first)->previous != NULL)
92+
*first = (*first)->previous;
93+
}
94+
95+
static void add_arg_to_input_list(struct trailer_item *on_tok,
96+
struct trailer_item *arg_tok,
97+
struct trailer_item **first,
98+
struct trailer_item **last)
99+
{
100+
if (after_or_end(arg_tok->conf.where)) {
101+
arg_tok->next = on_tok->next;
102+
on_tok->next = arg_tok;
103+
arg_tok->previous = on_tok;
104+
if (arg_tok->next)
105+
arg_tok->next->previous = arg_tok;
106+
update_last(last);
107+
} else {
108+
arg_tok->previous = on_tok->previous;
109+
on_tok->previous = arg_tok;
110+
arg_tok->next = on_tok;
111+
if (arg_tok->previous)
112+
arg_tok->previous->next = arg_tok;
113+
update_first(first);
114+
}
115+
}
116+
117+
static int check_if_different(struct trailer_item *in_tok,
118+
struct trailer_item *arg_tok,
119+
int check_all)
120+
{
121+
enum action_where where = arg_tok->conf.where;
122+
do {
123+
if (!in_tok)
124+
return 1;
125+
if (same_trailer(in_tok, arg_tok))
126+
return 0;
127+
/*
128+
* if we want to add a trailer after another one,
129+
* we have to check those before this one
130+
*/
131+
in_tok = after_or_end(where) ? in_tok->previous : in_tok->next;
132+
} while (check_all);
133+
return 1;
134+
}
135+
136+
static void remove_from_list(struct trailer_item *item,
137+
struct trailer_item **first,
138+
struct trailer_item **last)
139+
{
140+
struct trailer_item *next = item->next;
141+
struct trailer_item *previous = item->previous;
142+
143+
if (next) {
144+
item->next->previous = previous;
145+
item->next = NULL;
146+
} else if (last)
147+
*last = previous;
148+
149+
if (previous) {
150+
item->previous->next = next;
151+
item->previous = NULL;
152+
} else if (first)
153+
*first = next;
154+
}
155+
156+
static struct trailer_item *remove_first(struct trailer_item **first)
157+
{
158+
struct trailer_item *item = *first;
159+
*first = item->next;
160+
if (item->next) {
161+
item->next->previous = NULL;
162+
item->next = NULL;
163+
}
164+
return item;
165+
}
166+
167+
static void apply_arg_if_exists(struct trailer_item *in_tok,
168+
struct trailer_item *arg_tok,
169+
struct trailer_item *on_tok,
170+
struct trailer_item **in_tok_first,
171+
struct trailer_item **in_tok_last)
172+
{
173+
switch (arg_tok->conf.if_exists) {
174+
case EXISTS_DO_NOTHING:
175+
free_trailer_item(arg_tok);
176+
break;
177+
case EXISTS_REPLACE:
178+
add_arg_to_input_list(on_tok, arg_tok,
179+
in_tok_first, in_tok_last);
180+
remove_from_list(in_tok, in_tok_first, in_tok_last);
181+
free_trailer_item(in_tok);
182+
break;
183+
case EXISTS_ADD:
184+
add_arg_to_input_list(on_tok, arg_tok,
185+
in_tok_first, in_tok_last);
186+
break;
187+
case EXISTS_ADD_IF_DIFFERENT:
188+
if (check_if_different(in_tok, arg_tok, 1))
189+
add_arg_to_input_list(on_tok, arg_tok,
190+
in_tok_first, in_tok_last);
191+
else
192+
free_trailer_item(arg_tok);
193+
break;
194+
case EXISTS_ADD_IF_DIFFERENT_NEIGHBOR:
195+
if (check_if_different(on_tok, arg_tok, 0))
196+
add_arg_to_input_list(on_tok, arg_tok,
197+
in_tok_first, in_tok_last);
198+
else
199+
free_trailer_item(arg_tok);
200+
break;
201+
}
202+
}
203+
204+
static void apply_arg_if_missing(struct trailer_item **in_tok_first,
205+
struct trailer_item **in_tok_last,
206+
struct trailer_item *arg_tok)
207+
{
208+
struct trailer_item **in_tok;
209+
enum action_where where;
210+
211+
switch (arg_tok->conf.if_missing) {
212+
case MISSING_DO_NOTHING:
213+
free_trailer_item(arg_tok);
214+
break;
215+
case MISSING_ADD:
216+
where = arg_tok->conf.where;
217+
in_tok = after_or_end(where) ? in_tok_last : in_tok_first;
218+
if (*in_tok) {
219+
add_arg_to_input_list(*in_tok, arg_tok,
220+
in_tok_first, in_tok_last);
221+
} else {
222+
*in_tok_first = arg_tok;
223+
*in_tok_last = arg_tok;
224+
}
225+
break;
226+
}
227+
}
228+
229+
static int find_same_and_apply_arg(struct trailer_item **in_tok_first,
230+
struct trailer_item **in_tok_last,
231+
struct trailer_item *arg_tok)
232+
{
233+
struct trailer_item *in_tok;
234+
struct trailer_item *on_tok;
235+
struct trailer_item *following_tok;
236+
237+
enum action_where where = arg_tok->conf.where;
238+
int middle = (where == WHERE_AFTER) || (where == WHERE_BEFORE);
239+
int backwards = after_or_end(where);
240+
struct trailer_item *start_tok = backwards ? *in_tok_last : *in_tok_first;
241+
242+
for (in_tok = start_tok; in_tok; in_tok = following_tok) {
243+
following_tok = backwards ? in_tok->previous : in_tok->next;
244+
if (!same_token(in_tok, arg_tok))
245+
continue;
246+
on_tok = middle ? in_tok : start_tok;
247+
apply_arg_if_exists(in_tok, arg_tok, on_tok,
248+
in_tok_first, in_tok_last);
249+
return 1;
250+
}
251+
return 0;
252+
}
253+
254+
static void process_trailers_lists(struct trailer_item **in_tok_first,
255+
struct trailer_item **in_tok_last,
256+
struct trailer_item **arg_tok_first)
257+
{
258+
struct trailer_item *arg_tok;
259+
struct trailer_item *next_arg;
260+
261+
if (!*arg_tok_first)
262+
return;
263+
264+
for (arg_tok = *arg_tok_first; arg_tok; arg_tok = next_arg) {
265+
int applied = 0;
266+
267+
next_arg = arg_tok->next;
268+
remove_from_list(arg_tok, arg_tok_first, NULL);
269+
270+
applied = find_same_and_apply_arg(in_tok_first,
271+
in_tok_last,
272+
arg_tok);
273+
274+
if (!applied)
275+
apply_arg_if_missing(in_tok_first,
276+
in_tok_last,
277+
arg_tok);
278+
}
279+
}

0 commit comments

Comments
 (0)