2 * wiggle - apply rejected patches
4 * Copyright (C) 2005 Neil Brown <neilb@cse.unsw.edu.au>
5 * Copyright (C) 2010 Neil Brown <neilb@suse.de>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23 * Email: <neilb@suse.de>
30 * Second attempt at merging....
32 * We want to create a mergelist which identifies 'orig' and 'after'
33 * sections (from a and c) and conflicts (which are ranges of a,b,c which
35 * It is also helpful to differentiate 'orig' sections that aren't
36 * matched in 'b' with orig sections that are.
37 * To help with highlighting, it will be useful to know where
38 * the conflicts match the csl lists.
40 * This can all be achieved with a list of (a,b,c,c1,c1) 5-tuples.
41 * If two consecutive differ in more than one of a,b,c, it is a
43 * If only 'a' differ, it is un-matched original.
44 * If only 'b' differ, it is matched, unchanged original
45 * If only 'c' differ, it is 1
48 static inline int min(int a, int b)
52 static inline void assert(int a)
58 static int check_alreadyapplied(struct file af, struct file cf,
64 for (i = 0; i < m->al; i++) {
65 if (af.list[m->a+i].len != cf.list[m->c+i].len)
67 if (strncmp(af.list[m->a+i].start,
68 cf.list[m->c+i].start,
69 af.list[m->a+i].len) != 0)
73 printf("already applied %d,%d,%d - %d,%d,%d\n",
74 m->a, m->b, m->c, m->al, m->bl, m->cl);
75 printf(" %.10s - %.10s\n", af.list[m->a].start,
78 m->type = AlreadyApplied;
82 static int isolate_conflicts(struct file af, struct file bf, struct file cf,
83 struct csl *csl1, struct csl *csl2, int words,
84 struct merge *m, int show_wiggles)
86 /* A conflict indicates that something is definitely wrong
87 * and so we need to be a bit suspicious of nearby apparent matches.
88 * To display a conflict effectively we expands it's effect to
89 * include any Extraneous, Unmatched, Changed or AlreadyApplied text.
90 * Also, unless 'words', we need to include any partial lines
91 * in the Unchanged text that forms the border of a conflict.
93 * A Changed text may also border a conflict, but it can
94 * only border one conflict (where as an Unchanged can border
95 * a preceeding and a following conflict).
96 * The 'new' section of a Changed text appears in the
97 * conflict as does any part of the original before
100 * If 'show_wiggles' is set we treat wiggles like conflicts.
101 * A 'wiggle' is implied by any Extraneous text being ignored,
102 * or any line that has both Changed and Unmatched content.
103 * (Unmatched content where nothing is changed is common and not
104 * really a 'wiggle').
106 * A hunk header is never considered part of a conflict. It
107 * thereby can serve as a separator between conflicts.
114 for (i = 0; m[i].type != End; i++) {
115 if (m[i].type == Changed)
117 if (m[i].type == Unmatched)
119 if (m[i].type == Conflict ||
120 (show_wiggles && ((changed && unmatched)
121 || m[i].type == Extraneous))) {
122 /* We have a conflict (or wiggle) here.
123 * First search backwards for an Unchanged marking
124 * things as in_conflict. Then find the
125 * cut-point in the Unchanged. If there isn't one,
128 * Then search forward doing the same thing.
131 m[i].in_conflict = 1;
134 if (!m[j].in_conflict) {
135 m[j].in_conflict = 1;
137 } else if (m[j].type == Changed) {
138 /* This can no longer form a border */
140 /* We merge these conflicts and stop searching */
145 if (m[j].type == Unchanged || m[j].type == Changed) {
150 /* need to find the last line-break, which
151 * might be after the last newline, if there
152 * is one, or might be at the start
154 for (k = m[j].al; k > 0; k--)
155 if (ends_line(af.list[m[j].a+k-1]))
159 else if ((m[j].a == 0 || ends_line(af.list[m[j].a-1])) &&
160 (m[j].b == 0 || ends_line(bf.list[m[j].b-1])) &&
161 (m[j].c == 0 || ends_line(cf.list[m[j].c-1])))
164 /* no start-of-line found... */
166 if (m[j].hi > 0 && m[j].type == Changed) {
167 /* this can only work if start is also a line break */
168 if ((m[j].a == 0 || ends_line(af.list[m[j].a-1])) &&
169 (m[j].b == 0 || ends_line(bf.list[m[j].b-1])) &&
170 (m[j].c == 0 || ends_line(cf.list[m[j].c-1])))
180 /* now the forward search */
181 for (j = i+1; m[j].type != End; j++) {
182 m[j].in_conflict = 1;
183 if (m[j].type == Unchanged || m[j].type == Changed) {
189 /* need to find a line-break, which might be at
190 * the very beginning, or might be after the
191 * first newline - if there is one
193 if ((m[j].a == 0 || ends_line(af.list[m[j].a-1])) &&
194 (m[j].b == 0 || ends_line(bf.list[m[j].b-1])) &&
195 (m[j].c == 0 || ends_line(cf.list[m[j].c-1])))
198 for (k = 0 ; k < m[j].al ; k++)
199 if (ends_line(af.list[m[j].a+k]))
204 /* no start-of-line found */
207 if (m[j].lo <= m[j].al+1 && m[j].type == Changed) {
208 /* this can only work if the end is a line break */
209 if (ends_line(af.list[m[j].a+m[j].al-1]) &&
210 ends_line(bf.list[m[j].b+m[j].bl-1]) &&
211 ends_line(cf.list[m[j].c+m[j].cl-1]))
216 if (m[j].lo < m[j].al+1)
222 if (ends_line(af.list[m[i].a+m[i].al-1])) {
230 struct ci make_merger(struct file af, struct file bf, struct file cf,
231 struct csl *csl1, struct csl *csl2, int words,
232 int ignore_already, int show_wiggles)
234 /* find the wiggles and conflicts between csl1 and csl2
239 int wiggle_found = 0;
241 rv.conflicts = rv.wiggles = rv.ignored = 0;
243 for (i = 0; csl1[i].len; i++)
246 for (i = 0; csl2[i].len; i++)
249 /* maybe a bit of slack at each end */
252 rv.merger = xmalloc(sizeof(struct merge)*l);
254 a = b = c = c1 = c2 = 0;
258 match1 = (a >= csl1[c1].a && b >= csl1[c1].b); /* c1 doesn't match */
259 match2 = (b >= csl2[c2].a && c >= csl2[c2].b);
264 rv.merger[i].c1 = c1;
265 rv.merger[i].c2 = c2;
266 rv.merger[i].in_conflict = 0;
268 if (!match1 && match2) {
269 if (a < csl1[c1].a) {
270 /* some unmatched text */
271 rv.merger[i].type = Unmatched;
272 rv.merger[i].al = csl1[c1].a - a;
279 assert(b < csl1[c1].b);
280 /* some Extraneous text */
281 /* length is min of unmatched on left
282 * and matched on right.
283 * However a hunk-header is not allowed
284 * in the middle of an extraneous section,
287 rv.merger[i].type = Extraneous;
291 csl2[c2].len - (b-csl2[c2].a));
292 for (j = b; j < newb; j++) {
293 if (bf.list[j].start[0] == '\0') {
294 if (wiggle_found > 1)
303 rv.merger[i].bl = newb - b;
305 } else if (match1 && !match2) {
307 * if 'c' is currently at a suitable cut-point, then
308 * we can look for a triple-cut-point for start.
309 * Also, if csl2[c2].b isn't in a conflict, and is
310 * a suitable cut-point, then we could make a
311 * triple-cut-point for end of a conflict.
314 rv.merger[i].type = Changed;
315 rv.merger[i].bl = min(csl1[c1].b+csl1[c1].len, csl2[c2].a) - b;
316 rv.merger[i].al = rv.merger[i].bl;
317 rv.merger[i].cl = csl2[c2].b - c;
318 } else if (match1 && match2) {
319 /* Some unchanged text
321 rv.merger[i].type = Unchanged;
323 min(csl1[c1].len - (b-csl1[c1].b),
324 csl2[c2].len - (b-csl2[c2].a));
325 rv.merger[i].al = rv.merger[i].cl =
328 /* must be a conflict.
329 * Move a and c to next match, and b to closest of the two
331 rv.merger[i].type = Conflict;
332 rv.merger[i].al = csl1[c1].a - a;
333 rv.merger[i].cl = csl2[c2].b - c;
334 rv.merger[i].bl = min(csl1[c1].b, csl2[c2].a) - b;
335 if (ignore_already &&
336 check_alreadyapplied(af, cf, &rv.merger[i]))
339 a += rv.merger[i].al;
340 b += rv.merger[i].bl;
341 c += rv.merger[i].cl;
344 while (csl1[c1].a + csl1[c1].len <= a && csl1[c1].len)
346 assert(csl1[c1].b + csl1[c1].len >= b);
347 while (csl2[c2].b + csl2[c2].len <= c && csl2[c2].len)
349 assert(csl2[c2].a + csl2[c2].len >= b);
350 if (csl1[c1].len == 0 && csl2[c2].len == 0 &&
351 a == csl1[c1].a && b == csl1[c1].b &&
352 b == csl2[c2].a && c == csl2[c2].b)
355 rv.merger[i].type = End;
356 rv.merger[i].in_conflict = 0;
358 rv.conflicts = isolate_conflicts(af, bf, cf, csl1, csl2, words,
359 rv.merger, show_wiggles);
365 static void printrange(FILE *out, struct file *f, int start, int len)
368 printword(out, f->list[start]);
374 struct ci print_merge2(FILE *out, struct file *a, struct file *b, struct file *c,
375 struct csl *c1, struct csl *c2,
376 int words, int ignore_already, int show_wiggles)
378 struct ci rv = make_merger(*a, *b, *c, c1, c2,
379 words, ignore_already, show_wiggles);
382 for (m = rv.merger; m->type != End ; m++) {
385 printf("[%s: %d-%d,%d-%d,%d-%d%s(%d,%d)]\n",
386 m->type==Unmatched ? "Unmatched" :
387 m->type==Unchanged ? "Unchanged" :
388 m->type==Extraneous ? "Extraneous" :
389 m->type==Changed ? "Changed" :
390 m->type==AlreadyApplied ? "AlreadyApplied" :
391 m->type==Conflict ? "Conflict":"unknown",
395 m->in_conflict ? " in_conflict" : "",
398 while (m->in_conflict) {
399 /* need to print from 'hi' to 'lo' of next
400 * Unchanged which is < it's hi
402 int found_conflict = 0;
404 if (m->type == Unchanged || m->type == Changed)
409 if (m->type == Unchanged)
410 printrange(out, a, m->a+m->lo, m->hi - m->lo);
413 for (cm = m; cm->in_conflict; cm++) {
414 printf("{%s: %d-%d,%d-%d,%d-%d%s(%d,%d)}\n",
415 cm->type==Unmatched?"Unmatched":
416 cm->type==Unchanged?"Unchanged":
417 cm->type==Extraneous?"Extraneous":
418 cm->type==Changed?"Changed":
419 cm->type==AlreadyApplied?"AlreadyApplied":
420 cm->type==Conflict?"Conflict":"unknown",
421 cm->a, cm->a+cm->al-1,
422 cm->b, cm->b+cm->bl-1,
423 cm->c, cm->c+cm->cl-1,
424 cm->in_conflict ? " in_conflict" : "",
426 if ((cm->type == Unchanged || cm->type == Changed)
427 && cm != m && cm->lo < cm->hi)
431 fputs(words ? "<<<---" : "<<<<<<<\n", out);
432 for (cm = m; cm->in_conflict; cm++) {
433 if (cm->type == Conflict)
435 if ((cm->type == Unchanged || cm->type == Changed)
436 && cm != m && cm->lo < cm->hi) {
437 printrange(out, a, cm->a, cm->lo);
440 printrange(out, a, cm->a+st1, cm->al-st1);
443 fputs(words ? "|||" : "|||||||\n", out);
445 for (cm = m; cm->in_conflict; cm++) {
446 if ((cm->type == Unchanged || cm->type == Changed)
447 && cm != m && cm->lo < cm->hi) {
448 printrange(out, b, cm->b, cm->lo);
451 printrange(out, b, cm->b+st1, cm->bl-st1);
454 fputs(words ? "===" : "=======\n", out);
456 for (cm = m; cm->in_conflict; cm++) {
457 if (cm->type == Unchanged &&
458 cm != m && cm->lo < cm->hi) {
459 printrange(out, c, cm->c, cm->lo);
462 if (cm->type == Changed)
463 st1 = 0; /* All of result of change must be printed */
464 printrange(out, c, cm->c+st1, cm->cl-st1);
467 if (!found_conflict) {
468 /* This section was wiggled in successfully,
469 * but full conflict display was requested.
470 * So now print out the wiggled result as well.
472 fputs(words ? "&&&" : "&&&&&&&\n", out);
474 for (cm = m; cm->in_conflict; cm++) {
476 if ((cm->type == Unchanged || cm->type == Changed)
477 && cm != m && cm->lo < cm->hi)
483 printrange(out, a, cm->a+st1,
484 last ? cm->lo : cm->al-st1);
489 printrange(out, c, cm->c+st1,
490 last ? cm->lo : cm->cl-st1);
501 fputs(words ? "--->>>" : ">>>>>>>\n", out);
503 if (m->in_conflict && m->type == Unchanged
505 printrange(out, a, m->a+m->lo, m->hi-m->lo);
510 /* there is always some non-conflict after a conflict,
511 * unless we hit the end
517 printf("<<%s: %d-%d,%d-%d,%d-%d%s(%d,%d)>>\n",
518 m->type==Unmatched?"Unmatched":
519 m->type==Unchanged?"Unchanged":
520 m->type==Extraneous?"Extraneous":
521 m->type==Changed?"Changed":
522 m->type==AlreadyApplied?"AlreadyApplied":
523 m->type==Conflict?"Conflict":"unknown",
527 m->in_conflict ? " in_conflict" : "",
535 printrange(out, a, m->a, m->al);
540 printrange(out, c, m->c, m->cl);