File Coverage

deps/libgit2/src/xdiff/xmerge.c
Criterion Covered Total %
statement 249 429 58.0
branch 162 342 47.3
condition n/a
subroutine n/a
pod n/a
total 411 771 53.3


line stmt bran cond sub pod time code
1             /*
2             * LibXDiff by Davide Libenzi ( File Differential Library )
3             * Copyright (C) 2003-2006 Davide Libenzi, Johannes E. Schindelin
4             *
5             * This library is free software; you can redistribute it and/or
6             * modify it under the terms of the GNU Lesser General Public
7             * License as published by the Free Software Foundation; either
8             * version 2.1 of the License, or (at your option) any later version.
9             *
10             * This library is distributed in the hope that it will be useful,
11             * but WITHOUT ANY WARRANTY; without even the implied warranty of
12             * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13             * Lesser General Public License for more details.
14             *
15             * You should have received a copy of the GNU Lesser General Public
16             * License along with this library; if not, see
17             * .
18             *
19             * Davide Libenzi
20             *
21             */
22              
23             #include "xinclude.h"
24              
25             typedef struct s_xdmerge {
26             struct s_xdmerge *next;
27             /*
28             * 0 = conflict,
29             * 1 = no conflict, take first,
30             * 2 = no conflict, take second.
31             * 3 = no conflict, take both.
32             */
33             int mode;
34             /*
35             * These point at the respective postimages. E.g. is
36             * how side #1 wants to change the common ancestor; if there is no
37             * overlap, lines before i1 in the postimage of side #1 appear
38             * in the merge result as a region touched by neither side.
39             */
40             long i1, i2;
41             long chg1, chg2;
42             /*
43             * These point at the preimage; of course there is just one
44             * preimage, that is from the shared common ancestor.
45             */
46             long i0;
47             long chg0;
48             } xdmerge_t;
49              
50 11           static int xdl_append_merge(xdmerge_t **merge, int mode,
51             long i0, long chg0,
52             long i1, long chg1,
53             long i2, long chg2)
54             {
55 11           xdmerge_t *m = *merge;
56 11 50         if (m && (i1 <= m->i1 + m->chg1 || i2 <= m->i2 + m->chg2)) {
    0          
    0          
57 0 0         if (mode != m->mode)
58 0           m->mode = 0;
59 0           m->chg0 = i0 + chg0 - m->i0;
60 0           m->chg1 = i1 + chg1 - m->i1;
61 0           m->chg2 = i2 + chg2 - m->i2;
62             } else {
63 11           m = xdl_malloc(sizeof(xdmerge_t));
64 11 50         if (!m)
65 0           return -1;
66 11           m->next = NULL;
67 11           m->mode = mode;
68 11           m->i0 = i0;
69 11           m->chg0 = chg0;
70 11           m->i1 = i1;
71 11           m->chg1 = chg1;
72 11           m->i2 = i2;
73 11           m->chg2 = chg2;
74 11 50         if (*merge)
75 0           (*merge)->next = m;
76 11           *merge = m;
77             }
78 11           return 0;
79             }
80              
81 11           static int xdl_cleanup_merge(xdmerge_t *c)
82             {
83 11           int count = 0;
84             xdmerge_t *next_c;
85              
86             /* were there conflicts? */
87 22 100         for (; c; c = next_c) {
88 11 100         if (c->mode == 0)
89 8           count++;
90 11           next_c = c->next;
91 11           free(c);
92             }
93 11           return count;
94             }
95              
96 9           static int xdl_merge_cmp_lines(xdfenv_t *xe1, int i1, xdfenv_t *xe2, int i2,
97             int line_count, long flags)
98             {
99             int i;
100 9           xrecord_t **rec1 = xe1->xdf2.recs + i1;
101 9           xrecord_t **rec2 = xe2->xdf2.recs + i2;
102              
103 9 50         for (i = 0; i < line_count; i++) {
104 9           int result = xdl_recmatch(rec1[i]->ptr, rec1[i]->size,
105 18           rec2[i]->ptr, rec2[i]->size, flags);
106 9 50         if (!result)
107 9           return -1;
108             }
109 0           return 0;
110             }
111              
112 82           static int xdl_recs_copy_0(size_t *out, int use_orig, xdfenv_t *xe, int i, int count, int needs_cr, int add_nl, char *dest)
113             {
114             xrecord_t **recs;
115 82           size_t size = 0;
116              
117 82           *out = 0;
118              
119 82 50         recs = (use_orig ? xe->xdf1.recs : xe->xdf2.recs) + i;
120              
121 82 100         if (count < 1)
122 40           return 0;
123              
124 88 100         for (i = 0; i < count; ) {
125 46 100         if (dest)
126 23           memcpy(dest + size, recs[i]->ptr, recs[i]->size);
127              
128 46 50         GIT_ERROR_CHECK_ALLOC_ADD(&size, size, recs[i++]->size);
    50          
129             }
130              
131 42 100         if (add_nl) {
132 32           i = recs[count - 1]->size;
133 32 50         if (i == 0 || recs[count - 1]->ptr[i - 1] != '\n') {
    50          
134 32 50         if (needs_cr) {
135 0 0         if (dest)
136 0           dest[size] = '\r';
137 0 0         GIT_ERROR_CHECK_ALLOC_ADD(&size, size, 1);
    0          
138             }
139              
140 32 100         if (dest)
141 16           dest[size] = '\n';
142              
143 32 50         GIT_ERROR_CHECK_ALLOC_ADD(&size, size, 1);
    50          
144             }
145             }
146              
147 42           *out = size;
148 82           return 0;
149             }
150              
151 82           static int xdl_recs_copy(size_t *out, xdfenv_t *xe, int i, int count, int needs_cr, int add_nl, char *dest)
152             {
153 82           return xdl_recs_copy_0(out, 0, xe, i, count, needs_cr, add_nl, dest);
154             }
155              
156 0           static int xdl_orig_copy(size_t *out, xdfenv_t *xe, int i, int count, int needs_cr, int add_nl, char *dest)
157             {
158 0           return xdl_recs_copy_0(out, 1, xe, i, count, needs_cr, add_nl, dest);
159             }
160              
161             /*
162             * Returns 1 if the i'th line ends in CR/LF (if it is the last line and
163             * has no eol, the preceding line, if any), 0 if it ends in LF-only, and
164             * -1 if the line ending cannot be determined.
165             */
166 52           static int is_eol_crlf(xdfile_t *file, int i)
167             {
168             long size;
169              
170 52 100         if (i < file->nrec - 1)
171             /* All lines before the last *must* end in LF */
172 4 50         return (size = file->recs[i]->size) > 1 &&
    50          
173 4           file->recs[i]->ptr[size - 2] == '\r';
174 48 50         if (!file->nrec)
175             /* Cannot determine eol style from empty file */
176 0           return -1;
177 48 50         if ((size = file->recs[i]->size) &&
    50          
178 48           file->recs[i]->ptr[size - 1] == '\n')
179             /* Last line; ends in LF; Is it CR/LF? */
180 0 0         return size > 1 &&
    0          
181 0           file->recs[i]->ptr[size - 2] == '\r';
182 48 50         if (!i)
183             /* The only line has no eol */
184 48           return -1;
185             /* Determine eol from second-to-last line */
186 0 0         return (size = file->recs[i - 1]->size) > 1 &&
    0          
187 0           file->recs[i - 1]->ptr[size - 2] == '\r';
188             }
189              
190 20           static int is_cr_needed(xdfenv_t *xe1, xdfenv_t *xe2, xdmerge_t *m)
191             {
192             int needs_cr;
193              
194             /* Match post-images' preceding, or first, lines' end-of-line style */
195 20 100         needs_cr = is_eol_crlf(&xe1->xdf2, m->i1 ? m->i1 - 1 : 0);
196 20 100         if (needs_cr)
197 16 50         needs_cr = is_eol_crlf(&xe2->xdf2, m->i2 ? m->i2 - 1 : 0);
198             /* Look at pre-image's first line, unless we already settled on LF */
199 20 100         if (needs_cr)
200 16           needs_cr = is_eol_crlf(&xe1->xdf1, 0);
201             /* If still undecided, use LF-only */
202 20           return needs_cr < 0 ? 0 : needs_cr;
203             }
204              
205 16           static int fill_conflict_hunk(size_t *out, xdfenv_t *xe1, const char *name1,
206             xdfenv_t *xe2, const char *name2,
207             const char *name3,
208             size_t size, int i, int style,
209             xdmerge_t *m, char *dest, int marker_size)
210             {
211 16 50         int marker1_size = (name1 ? (int)strlen(name1) + 1 : 0);
212 16 50         int marker2_size = (name2 ? (int)strlen(name2) + 1 : 0);
213 16 50         int marker3_size = (name3 ? (int)strlen(name3) + 1 : 0);
214 16           int needs_cr = is_cr_needed(xe1, xe2, m);
215             size_t copied;
216              
217 16           *out = 0;
218              
219 16 100         if (marker_size <= 0)
220 14           marker_size = DEFAULT_CONFLICT_MARKER_SIZE;
221              
222             /* Before conflicting part */
223 16 100         if (xdl_recs_copy(&copied, xe1, i, m->i1 - i, 0, 0,
    50          
224 8           dest ? dest + size : NULL) < 0)
225 0           return -1;
226              
227 16 50         GIT_ERROR_CHECK_ALLOC_ADD(&size, size, copied);
    50          
228              
229 16 100         if (!dest) {
230 8 50         GIT_ERROR_CHECK_ALLOC_ADD5(&size, size, marker_size, 1, needs_cr, marker1_size);
    50          
    50          
    50          
231             } else {
232 8           memset(dest + size, '<', marker_size);
233 8           size += marker_size;
234 8 50         if (marker1_size) {
235 8           dest[size] = ' ';
236 8           memcpy(dest + size + 1, name1, marker1_size - 1);
237 8           size += marker1_size;
238             }
239 8 50         if (needs_cr)
240 0           dest[size++] = '\r';
241 8           dest[size++] = '\n';
242             }
243              
244             /* Postimage from side #1 */
245 16 100         if (xdl_recs_copy(&copied, xe1, m->i1, m->chg1, needs_cr, 1,
    50          
246 8           dest ? dest + size : NULL) < 0)
247 0           return -1;
248              
249 16 50         GIT_ERROR_CHECK_ALLOC_ADD(&size, size, copied);
    50          
250              
251 16 50         if (style == XDL_MERGE_DIFF3) {
252             /* Shared preimage */
253 0 0         if (!dest) {
254 0 0         GIT_ERROR_CHECK_ALLOC_ADD5(&size, size, marker_size, 1, needs_cr, marker3_size);
    0          
    0          
    0          
255             } else {
256 0           memset(dest + size, '|', marker_size);
257 0           size += marker_size;
258 0 0         if (marker3_size) {
259 0           dest[size] = ' ';
260 0           memcpy(dest + size + 1, name3, marker3_size - 1);
261 0           size += marker3_size;
262             }
263 0 0         if (needs_cr)
264 0           dest[size++] = '\r';
265 0           dest[size++] = '\n';
266             }
267              
268 0 0         if (xdl_orig_copy(&copied, xe1, m->i0, m->chg0, needs_cr, 1,
    0          
269 0           dest ? dest + size : NULL) < 0)
270 0           return -1;
271 0 0         GIT_ERROR_CHECK_ALLOC_ADD(&size, size, copied);
    0          
272             }
273              
274 16 100         if (!dest) {
275 8 50         GIT_ERROR_CHECK_ALLOC_ADD4(&size, size, marker_size, 1, needs_cr);
    50          
    50          
276             } else {
277 8           memset(dest + size, '=', marker_size);
278 8           size += marker_size;
279 8 50         if (needs_cr)
280 0           dest[size++] = '\r';
281 8           dest[size++] = '\n';
282             }
283              
284             /* Postimage from side #2 */
285              
286 16 100         if (xdl_recs_copy(&copied, xe2, m->i2, m->chg2, needs_cr, 1,
    50          
287 8           dest ? dest + size : NULL) < 0)
288 0           return -1;
289 16 50         GIT_ERROR_CHECK_ALLOC_ADD(&size, size, copied);
    50          
290              
291 16 100         if (!dest) {
292 8 50         GIT_ERROR_CHECK_ALLOC_ADD5(&size, size, marker_size, 1, needs_cr, marker2_size);
    50          
    50          
    50          
293             } else {
294 8           memset(dest + size, '>', marker_size);
295 8           size += marker_size;
296 8 50         if (marker2_size) {
297 8           dest[size] = ' ';
298 8           memcpy(dest + size + 1, name2, marker2_size - 1);
299 8           size += marker2_size;
300             }
301 8 50         if (needs_cr)
302 0           dest[size++] = '\r';
303 8           dest[size++] = '\n';
304             }
305              
306 16           *out = size;
307 16           return 0;
308             }
309              
310 22           static int xdl_fill_merge_buffer(size_t *out,
311             xdfenv_t *xe1, const char *name1,
312             xdfenv_t *xe2, const char *name2,
313             const char *ancestor_name,
314             int favor,
315             xdmerge_t *m, char *dest, int style,
316             int marker_size)
317             {
318             size_t size, copied;
319             int i;
320              
321 22           *out = 0;
322              
323 44 100         for (size = i = 0; m; m = m->next) {
324 22 100         if (favor && !m->mode)
    100          
325 3           m->mode = favor;
326              
327 22 100         if (m->mode == 0) {
328 16 50         if (fill_conflict_hunk(&size, xe1, name1, xe2, name2,
329             ancestor_name,
330             size, i, style, m, dest,
331             marker_size) < 0)
332 0           return -1;
333             }
334 6 50         else if (m->mode & 3) {
335             /* Before conflicting part */
336 6 100         if (xdl_recs_copy(&copied, xe1, i, m->i1 - i, 0, 0,
    50          
337 3           dest ? dest + size : NULL) < 0)
338 0           return -1;
339 6 50         GIT_ERROR_CHECK_ALLOC_ADD(&size, size, copied);
    50          
340              
341             /* Postimage from side #1 */
342 6 100         if (m->mode & 1) {
343 4           int needs_cr = is_cr_needed(xe1, xe2, m);
344              
345 4 100         if (xdl_recs_copy(&copied, xe1, m->i1, m->chg1, needs_cr, (m->mode & 2),
    50          
346 2           dest ? dest + size : NULL) < 0)
347 0           return -1;
348 4 50         GIT_ERROR_CHECK_ALLOC_ADD(&size, size, copied);
    50          
349             }
350              
351             /* Postimage from side #2 */
352 6 100         if (m->mode & 2) {
353 2 100         if (xdl_recs_copy(&copied, xe2, m->i2, m->chg2, 0, 0,
    50          
354 1           dest ? dest + size : NULL) < 0)
355 0           return -1;
356 2 50         GIT_ERROR_CHECK_ALLOC_ADD(&size, size, copied);
    50          
357             }
358             } else
359 0           continue;
360 22           i = m->i1 + m->chg1;
361             }
362              
363 22 100         if (xdl_recs_copy(&copied, xe1, i, xe1->xdf2.nrec - i, 0, 0,
    50          
364 11           dest ? dest + size : NULL) < 0)
365 0           return -1;
366 22 50         GIT_ERROR_CHECK_ALLOC_ADD(&size, size, copied);
    50          
367              
368 22           *out = size;
369 22           return 0;
370             }
371              
372             /*
373             * Sometimes, changes are not quite identical, but differ in only a few
374             * lines. Try hard to show only these few lines as conflicting.
375             */
376 11           static int xdl_refine_conflicts(xdfenv_t *xe1, xdfenv_t *xe2, xdmerge_t *m,
377             xpparam_t const *xpp)
378             {
379 22 100         for (; m; m = m->next) {
380             mmfile_t t1, t2;
381             xdfenv_t xe;
382             xdchange_t *xscr, *x;
383 11           int i1 = m->i1, i2 = m->i2;
384              
385             /* let's handle just the conflicts */
386 11 50         if (m->mode)
387 0           continue;
388              
389             /* no sense refining a conflict when one side is empty */
390 11 50         if (m->chg1 == 0 || m->chg2 == 0)
    50          
391 0           continue;
392              
393             /*
394             * This probably does not work outside git, since
395             * we have a very simple mmfile structure.
396             */
397 11           t1.ptr = (char *)xe1->xdf2.recs[m->i1]->ptr;
398 22           t1.size = xe1->xdf2.recs[m->i1 + m->chg1 - 1]->ptr
399 11           + xe1->xdf2.recs[m->i1 + m->chg1 - 1]->size - t1.ptr;
400 11           t2.ptr = (char *)xe2->xdf2.recs[m->i2]->ptr;
401 22           t2.size = xe2->xdf2.recs[m->i2 + m->chg2 - 1]->ptr
402 11           + xe2->xdf2.recs[m->i2 + m->chg2 - 1]->size - t2.ptr;
403 11 50         if (xdl_do_diff(&t1, &t2, xpp, &xe) < 0)
404 0           return -1;
405 22           if (xdl_change_compact(&xe.xdf1, &xe.xdf2, xpp->flags) < 0 ||
406 22 50         xdl_change_compact(&xe.xdf2, &xe.xdf1, xpp->flags) < 0 ||
407 11           xdl_build_script(&xe, &xscr) < 0) {
408 0           xdl_free_env(&xe);
409 0           return -1;
410             }
411 11 50         if (!xscr) {
412             /* If this happens, the changes are identical. */
413 0           xdl_free_env(&xe);
414 0           m->mode = 4;
415 0           continue;
416             }
417 11           x = xscr;
418 11           m->i1 = xscr->i1 + i1;
419 11           m->chg1 = xscr->chg1;
420 11           m->i2 = xscr->i2 + i2;
421 11           m->chg2 = xscr->chg2;
422 11 50         while (xscr->next) {
423 0           xdmerge_t *m2 = xdl_malloc(sizeof(xdmerge_t));
424 0 0         if (!m2) {
425 0           xdl_free_env(&xe);
426 0           xdl_free_script(x);
427 0           return -1;
428             }
429 0           xscr = xscr->next;
430 0           m2->next = m->next;
431 0           m->next = m2;
432 0           m = m2;
433 0           m->mode = 0;
434 0           m->i1 = xscr->i1 + i1;
435 0           m->chg1 = xscr->chg1;
436 0           m->i2 = xscr->i2 + i2;
437 0           m->chg2 = xscr->chg2;
438             }
439 11           xdl_free_env(&xe);
440 11           xdl_free_script(x);
441             }
442 11           return 0;
443             }
444              
445 0           static int line_contains_alnum(const char *ptr, long size)
446             {
447 0 0         while (size--)
448 0 0         if (isalnum((unsigned char)*(ptr++)))
449 0           return 1;
450 0           return 0;
451             }
452              
453 0           static int lines_contain_alnum(xdfenv_t *xe, int i, int chg)
454             {
455 0 0         for (; chg; chg--, i++)
456 0 0         if (line_contains_alnum(xe->xdf2.recs[i]->ptr,
457 0           xe->xdf2.recs[i]->size))
458 0           return 1;
459 0           return 0;
460             }
461              
462             /*
463             * This function merges m and m->next, marking everything between those hunks
464             * as conflicting, too.
465             */
466 0           static void xdl_merge_two_conflicts(xdmerge_t *m)
467             {
468 0           xdmerge_t *next_m = m->next;
469 0           m->chg1 = next_m->i1 + next_m->chg1 - m->i1;
470 0           m->chg2 = next_m->i2 + next_m->chg2 - m->i2;
471 0           m->next = next_m->next;
472 0           free(next_m);
473 0           }
474              
475             /*
476             * If there are less than 3 non-conflicting lines between conflicts,
477             * it appears simpler -- because it takes up less (or as many) lines --
478             * if the lines are moved into the conflicts.
479             */
480 11           static int xdl_simplify_non_conflicts(xdfenv_t *xe1, xdmerge_t *m,
481             int simplify_if_no_alnum)
482             {
483 11           int result = 0;
484              
485 11 50         if (!m)
486 0           return result;
487             for (;;) {
488 11           xdmerge_t *next_m = m->next;
489             int begin, end;
490              
491 11 50         if (!next_m)
492 11           return result;
493              
494 0           begin = m->i1 + m->chg1;
495 0           end = next_m->i1;
496              
497 0 0         if (m->mode != 0 || next_m->mode != 0 ||
    0          
    0          
498 0 0         (end - begin > 3 &&
499 0 0         (!simplify_if_no_alnum ||
500 0           lines_contain_alnum(xe1, begin, end - begin)))) {
501 0           m = next_m;
502             } else {
503 0           result++;
504 0           xdl_merge_two_conflicts(m);
505             }
506 0           }
507             }
508              
509             /*
510             * level == 0: mark all overlapping changes as conflict
511             * level == 1: mark overlapping changes as conflict only if not identical
512             * level == 2: analyze non-identical changes for minimal conflict set
513             * level == 3: analyze non-identical changes for minimal conflict set, but
514             * treat hunks not containing any letter or number as conflicting
515             *
516             * returns < 0 on error, == 0 for no conflicts, else number of conflicts
517             */
518 11           static int xdl_do_merge(xdfenv_t *xe1, xdchange_t *xscr1,
519             xdfenv_t *xe2, xdchange_t *xscr2,
520             xmparam_t const *xmp, mmbuffer_t *result)
521             {
522             xdmerge_t *changes, *c;
523 11           xpparam_t const *xpp = &xmp->xpp;
524 11           const char *const ancestor_name = xmp->ancestor;
525 11           const char *const name1 = xmp->file1;
526 11           const char *const name2 = xmp->file2;
527             int i0, i1, i2, chg0, chg1, chg2;
528 11           int level = xmp->level;
529 11           int style = xmp->style;
530 11           int favor = xmp->favor;
531              
532 11 50         if (style == XDL_MERGE_DIFF3) {
533             /*
534             * "diff3 -m" output does not make sense for anything
535             * more aggressive than XDL_MERGE_EAGER.
536             */
537 0 0         if (XDL_MERGE_EAGER < level)
538 0           level = XDL_MERGE_EAGER;
539             }
540              
541 11           c = changes = NULL;
542              
543 22 100         while (xscr1 && xscr2) {
    50          
544 11 50         if (!changes)
545 11           changes = c;
546 11 50         if (xscr1->i1 + xscr1->chg1 < xscr2->i1) {
547 0           i0 = xscr1->i1;
548 0           i1 = xscr1->i2;
549 0           i2 = xscr2->i2 - xscr2->i1 + xscr1->i1;
550 0           chg0 = xscr1->chg1;
551 0           chg1 = xscr1->chg2;
552 0           chg2 = xscr1->chg1;
553 0 0         if (xdl_append_merge(&c, 1,
554             i0, chg0, i1, chg1, i2, chg2)) {
555 0           xdl_cleanup_merge(changes);
556 0           return -1;
557             }
558 0           xscr1 = xscr1->next;
559 0           continue;
560             }
561 11 50         if (xscr2->i1 + xscr2->chg1 < xscr1->i1) {
562 0           i0 = xscr2->i1;
563 0           i1 = xscr1->i2 - xscr1->i1 + xscr2->i1;
564 0           i2 = xscr2->i2;
565 0           chg0 = xscr2->chg1;
566 0           chg1 = xscr2->chg1;
567 0           chg2 = xscr2->chg2;
568 0 0         if (xdl_append_merge(&c, 2,
569             i0, chg0, i1, chg1, i2, chg2)) {
570 0           xdl_cleanup_merge(changes);
571 0           return -1;
572             }
573 0           xscr2 = xscr2->next;
574 0           continue;
575             }
576 11 50         if (level == XDL_MERGE_MINIMAL || xscr1->i1 != xscr2->i1 ||
    50          
    50          
577 11 100         xscr1->chg1 != xscr2->chg1 ||
578 9 50         xscr1->chg2 != xscr2->chg2 ||
579 9           xdl_merge_cmp_lines(xe1, xscr1->i2,
580 9           xe2, xscr2->i2,
581 18           xscr1->chg2, xpp->flags)) {
582             /* conflict */
583 11           int off = xscr1->i1 - xscr2->i1;
584 11           int ffo = off + xscr1->chg1 - xscr2->chg1;
585              
586 11           i0 = xscr1->i1;
587 11           i1 = xscr1->i2;
588 11           i2 = xscr2->i2;
589 11 50         if (off > 0) {
590 0           i0 -= off;
591 0           i1 -= off;
592             }
593             else
594 11           i2 += off;
595 11           chg0 = xscr1->i1 + xscr1->chg1 - i0;
596 11           chg1 = xscr1->i2 + xscr1->chg2 - i1;
597 11           chg2 = xscr2->i2 + xscr2->chg2 - i2;
598 11 50         if (ffo < 0) {
599 0           chg0 -= ffo;
600 0           chg1 -= ffo;
601             } else
602 11           chg2 += ffo;
603 11 50         if (xdl_append_merge(&c, 0,
604             i0, chg0, i1, chg1, i2, chg2)) {
605 0           xdl_cleanup_merge(changes);
606 0           return -1;
607             }
608             }
609              
610 11           i1 = xscr1->i1 + xscr1->chg1;
611 11           i2 = xscr2->i1 + xscr2->chg1;
612              
613 11 50         if (i1 >= i2)
614 11           xscr2 = xscr2->next;
615 11 50         if (i2 >= i1)
616 11           xscr1 = xscr1->next;
617             }
618 11 50         while (xscr1) {
619 0 0         if (!changes)
620 0           changes = c;
621 0           i0 = xscr1->i1;
622 0           i1 = xscr1->i2;
623 0           i2 = xscr1->i1 + xe2->xdf2.nrec - xe2->xdf1.nrec;
624 0           chg0 = xscr1->chg1;
625 0           chg1 = xscr1->chg2;
626 0           chg2 = xscr1->chg1;
627 0 0         if (xdl_append_merge(&c, 1,
628             i0, chg0, i1, chg1, i2, chg2)) {
629 0           xdl_cleanup_merge(changes);
630 0           return -1;
631             }
632 0           xscr1 = xscr1->next;
633             }
634 11 50         while (xscr2) {
635 0 0         if (!changes)
636 0           changes = c;
637 0           i0 = xscr2->i1;
638 0           i1 = xscr2->i1 + xe1->xdf2.nrec - xe1->xdf1.nrec;
639 0           i2 = xscr2->i2;
640 0           chg0 = xscr2->chg1;
641 0           chg1 = xscr2->chg1;
642 0           chg2 = xscr2->chg2;
643 0 0         if (xdl_append_merge(&c, 2,
644             i0, chg0, i1, chg1, i2, chg2)) {
645 0           xdl_cleanup_merge(changes);
646 0           return -1;
647             }
648 0           xscr2 = xscr2->next;
649             }
650 11 50         if (!changes)
651 11           changes = c;
652             /* refine conflicts */
653 22           if (XDL_MERGE_ZEALOUS <= level &&
654 22 50         (xdl_refine_conflicts(xe1, xe2, changes, xpp) < 0 ||
655 11           xdl_simplify_non_conflicts(xe1, changes,
656             XDL_MERGE_ZEALOUS < level) < 0)) {
657 0           xdl_cleanup_merge(changes);
658 0           return -1;
659             }
660             /* output */
661 11 50         if (result) {
662 11           int marker_size = xmp->marker_size;
663             size_t size;
664              
665 11 50         if (xdl_fill_merge_buffer(&size, xe1, name1, xe2, name2,
666             ancestor_name,
667             favor, changes, NULL, style,
668             marker_size) < 0)
669 0           return -1;
670              
671 11           result->ptr = xdl_malloc(size);
672 11 50         if (!result->ptr) {
673 0           xdl_cleanup_merge(changes);
674 0           return -1;
675             }
676 11           result->size = size;
677 11 50         if (xdl_fill_merge_buffer(&size, xe1, name1, xe2, name2,
678             ancestor_name, favor, changes,
679             result->ptr, style, marker_size) < 0)
680 11           return -1;
681             }
682 11           return xdl_cleanup_merge(changes);
683             }
684              
685 11           int xdl_merge(mmfile_t *orig, mmfile_t *mf1, mmfile_t *mf2,
686             xmparam_t const *xmp, mmbuffer_t *result)
687             {
688             xdchange_t *xscr1, *xscr2;
689             xdfenv_t xe1, xe2;
690             int status;
691 11           xpparam_t const *xpp = &xmp->xpp;
692              
693 11           result->ptr = NULL;
694 11           result->size = 0;
695              
696 11 50         if (xdl_do_diff(orig, mf1, xpp, &xe1) < 0) {
697 0           return -1;
698             }
699 11 50         if (xdl_do_diff(orig, mf2, xpp, &xe2) < 0) {
700 0           xdl_free_env(&xe1);
701 0           return -1;
702             }
703 22           if (xdl_change_compact(&xe1.xdf1, &xe1.xdf2, xpp->flags) < 0 ||
704 22 50         xdl_change_compact(&xe1.xdf2, &xe1.xdf1, xpp->flags) < 0 ||
705 11           xdl_build_script(&xe1, &xscr1) < 0) {
706 0           xdl_free_env(&xe1);
707 0           return -1;
708             }
709 22           if (xdl_change_compact(&xe2.xdf1, &xe2.xdf2, xpp->flags) < 0 ||
710 22 50         xdl_change_compact(&xe2.xdf2, &xe2.xdf1, xpp->flags) < 0 ||
711 11           xdl_build_script(&xe2, &xscr2) < 0) {
712 0           xdl_free_script(xscr1);
713 0           xdl_free_env(&xe1);
714 0           xdl_free_env(&xe2);
715 0           return -1;
716             }
717 11           status = 0;
718 11 50         if (!xscr1) {
719 0           result->ptr = xdl_malloc(mf2->size);
720 0 0         if (!result->ptr) {
721 0           xdl_free_script(xscr2);
722 0           xdl_free_env(&xe1);
723 0           xdl_free_env(&xe2);
724 0           return -1;
725             }
726 0           memcpy(result->ptr, mf2->ptr, mf2->size);
727 0           result->size = mf2->size;
728 11 50         } else if (!xscr2) {
729 0           result->ptr = xdl_malloc(mf1->size);
730 0 0         if (!result->ptr) {
731 0           xdl_free_script(xscr1);
732 0           xdl_free_env(&xe1);
733 0           xdl_free_env(&xe2);
734 0           return -1;
735             }
736 0           memcpy(result->ptr, mf1->ptr, mf1->size);
737 0           result->size = mf1->size;
738             } else {
739 11           status = xdl_do_merge(&xe1, xscr1,
740             &xe2, xscr2,
741             xmp, result);
742             }
743 11           xdl_free_script(xscr1);
744 11           xdl_free_script(xscr2);
745              
746 11           xdl_free_env(&xe1);
747 11           xdl_free_env(&xe2);
748              
749 11           return status;
750             }