2 * wiggle - apply rejected patches
4 * Copyright (C) 2005 Neil Brown <neilb@cse.unsw.edu.au>
5 * Copyright (C) 2010-2013 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.
22 * Email: <neilb@suse.de>
29 * Second attempt at merging....
31 * We want to create a mergelist which identifies 'orig' and 'after'
32 * sections (from a and c) and conflicts (which are ranges of a,b,c which
34 * It is also helpful to differentiate 'orig' sections that aren't
35 * matched in 'b' with orig sections that are.
36 * To help with highlighting, it will be useful to know where
37 * the conflicts match the csl lists.
39 * This can all be achieved with a list of (a,b,c,c1,c1) 5-tuples.
40 * If two consecutive differ in more than one of a,b,c, it is a
42 * If only 'a' differ, it is un-matched original.
43 * If only 'b' differ, it is matched, unchanged original
44 * If only 'c' differ, it is 1
47 static inline int min(int a
, int b
)
52 static int check_alreadyapplied(struct file af
, struct file cf
,
58 for (i
= 0; i
< m
->al
; i
++) {
59 if (af
.list
[m
->a
+i
].len
!= cf
.list
[m
->c
+i
].len
)
61 if (strncmp(af
.list
[m
->a
+i
].start
,
62 cf
.list
[m
->c
+i
].start
,
63 af
.list
[m
->a
+i
].len
) != 0)
67 printf("already applied %d,%d,%d - %d,%d,%d\n",
68 m
->a
, m
->b
, m
->c
, m
->al
, m
->bl
, m
->cl
);
69 printf(" %.10s - %.10s\n", af
.list
[m
->a
].start
,
72 m
->type
= AlreadyApplied
;
76 /* A 'cut-point' is a location in the merger where it is reasonable
77 * the change the mode of display - between displaying the merger
78 * and displaying the separate streams.
79 * A 'conflict' can only be displayed as separate stream so when
80 * one is found, we need to find a preceding and trailing cut-point
81 * and enlarge the conflict to that range.
82 * A suitable location is one where all three streams are at a line-end.
84 static int is_cutpoint(struct merge m
,
85 struct file af
, struct file bf
, struct file cf
)
87 return ((m
.a
== 0 || ends_line(af
.list
[m
.a
-1])) &&
88 (m
.b
== 0 || ends_line(bf
.list
[m
.b
-1])) &&
89 (m
.c
== 0 || ends_line(cf
.list
[m
.c
-1])));
92 int isolate_conflicts(struct file af
, struct file bf
, struct file cf
,
93 struct csl
*csl1
, struct csl
*csl2
, int words
,
94 struct merge
*m
, int show_wiggles
,
97 /* A Conflict indicates that something is definitely wrong
98 * and so we need to be a bit suspicious of nearby apparent matches.
99 * To display a conflict effectively we expands its effect to
100 * include any Extraneous, Unmatched, Changed or AlreadyApplied text.
101 * Also, unless 'words', we need to include any partial lines
102 * in the Unchanged text that forms the border of a conflict.
104 * A Changed text may also border a conflict, but it can
105 * only border one conflict (where as an Unchanged can border
106 * a preceding and a following conflict).
107 * The 'new' section of a Changed text appears in the
108 * conflict as does any part of the original before
111 * A hunk header (Extraneous) is never considered part of a
112 * conflict. It thereby can serve as a separator between
115 * Extended conflicts are marked by setting ->in_conflict in
116 * the "struct merge". This is '1' for an Unchanged, Changed,
117 * or (Extraneous) hunk header which borders the conflict,
118 * '2' for a merger which is truly in conflict, and '3' for
119 * a merger which is causing a 'wiggle'.
120 * When in_conflict == 1, the 'lo' and 'hi' fields indicate
121 * how much of the 'a' file is included in the conflict, the rest
122 * being part of the clean result.
123 * Elements in af from m->a to m->a+m->lo are in the preceding
124 * conflict, from m->a+m->lo to m->a+m->hi are clean, and
125 * m->a+m->hi to m->a+m->al are in the following conflict.
127 * We need to ensure there is adequate context for the conflict.
128 * So ensure there are at least 3 newlines in Extraneous or
129 * Unchanged on both sides of a Conflict - but don't go so far
130 * as including a hunk header.
131 * If there are 3, and they are all in 'Unchanged' sections, then
132 * that much context is not really needed - reduce it a bit.
134 * If a wiggle is adjacent to a conflict then:
135 * - if show_wiggles is set, we just merge them
136 * - if it is not set, we still want to count the wiggle.
139 int cnt
= 0, wiggles
= 0;
145 for (i
= 0; m
[i
].type
!= End
; i
++)
146 m
[i
].in_conflict
= 0;
148 for (i
= 0; m
[i
].type
!= End
; i
++) {
149 /* The '3' here is a count of newlines. Once we find
150 * that many newlines of the particular type, we have escaped.
152 if (m
[i
].type
== Changed
)
154 if (m
[i
].type
== Unmatched
)
156 if (m
[i
].type
== Extraneous
&& bf
.list
[m
[i
].b
].start
[0])
157 /* hunk headers don't imply wiggles, other
158 * extraneous text does.
162 if (m
[i
].type
!= Unchanged
&& changed
&& (unmatched
|| extraneous
)) {
169 if ((m
[i
].type
== Conflict
) ||
170 (show_wiggles
&& in_wiggle
)) {
171 /* We have a conflict or wiggle here.
172 * First search backwards for an Unchanged marking
173 * things as in_conflict. Then find the
174 * cut-point in the Unchanged. If there isn't one,
177 * Then search forward doing the same thing.
180 m
[i
].in_conflict
= m
[i
].type
== Conflict
? 2 : 3;
185 if (m
[j
].type
== Extraneous
&&
186 bf
.list
[m
[j
].b
].start
[0] == '\0')
187 /* hunk header - not conflict any more */
189 if (m
[j
].in_conflict
> 1)
190 /* Merge the conflicts */
192 if (!m
[j
].in_conflict
) {
193 m
[j
].in_conflict
= 1;
196 /* Following must set m[j].hi, or set
199 if (m
[j
].type
== Extraneous
) {
200 for (k
= m
[j
].bl
; k
> 0; k
--)
201 if (ends_line(bf
.list
[m
[j
].b
+k
-1]))
205 if (m
[j
].type
!= Unchanged
&&
206 m
[j
].type
!= Changed
) {
207 if (m
[j
].type
== Conflict
)
208 m
[j
].in_conflict
= 2;
210 m
[j
].in_conflict
= m
[i
].in_conflict
;
213 /* If we find enough newlines in this section,
214 * then we only really need 1, but would rather
215 * it wasn't the first one. 'firstk' allows us
216 * to track which newline we actually use
223 /* need to find the last line-break, which
224 * might be after the last newline, if there
225 * is one, or might be at the start
227 for (k
= m
[j
].al
; k
> 0; k
--) {
228 if (m
[j
].a
+ k
>= af
.elcnt
)
229 /* FIXME impossible!*/
231 if (ends_line(af
.list
[m
[j
].a
+k
-1])) {
232 if (firstk
> m
[j
].al
)
245 else if (is_cutpoint(m
[j
], af
,bf
,cf
))
248 /* no start-of-line found... */
251 (m
[j
].type
== Changed
)) {
252 /* this can only work if start is
253 * also a line break */
254 if (is_cutpoint(m
[j
], af
,bf
,cf
))
261 m
[j
].in_conflict
= m
[i
].in_conflict
;
264 /* now the forward search */
266 for (j
= i
+1; m
[j
].type
!= End
; j
++) {
267 if (m
[j
].type
== Extraneous
&&
268 bf
.list
[m
[j
].b
].start
[0] == '\0')
269 /* hunk header - not conflict any more */
271 if (m
[j
].type
== Extraneous
) {
272 for (k
= 0; k
< m
[j
].bl
; k
++)
273 if (ends_line(bf
.list
[m
[j
].b
+k
]))
276 if (m
[j
].type
!= Unchanged
&&
277 m
[j
].type
!= Changed
) {
278 if (m
[j
].type
== Conflict
)
279 m
[j
].in_conflict
= 2;
281 m
[j
].in_conflict
= m
[i
].in_conflict
;
284 m
[j
].in_conflict
= 1;
290 /* need to find a line-break, which might be at
291 * the very beginning, or might be after the
292 * first newline - if there is one
294 if (is_cutpoint(m
[j
], af
,bf
,cf
))
297 /* If we find enough newlines in this section,
298 * then we only really need 1, but would rather
299 * it wasn't the first one. 'firstk' allows us
300 * to track which newline we actually use
303 for (k
= 0 ; k
< m
[j
].al
; k
++)
304 if (ends_line(af
.list
[m
[j
].a
+k
])) {
315 /* Hit end of file, pretend we found 3 newlines. */
319 m
[j
+1].type
== Unmatched
) {
320 /* If this Unmatched exceeds 3 lines, just stop here */
323 for (p
= 0; p
< m
[j
+1].al
; p
++)
324 if (ends_line(af
.list
[m
[j
+1].a
+p
])) {
335 /* no start-of-line found */
338 if (m
[j
].lo
<= m
[j
].al
+1 &&
339 (m
[j
].type
== Changed
)) {
340 /* this can only work if the end is a line break */
341 if (is_cutpoint(m
[j
+1], af
,bf
,cf
))
346 if (m
[j
].lo
< m
[j
].al
+1)
348 m
[j
].in_conflict
= m
[i
].in_conflict
;
350 if (m
[j
-1].in_conflict
== 1)
353 /* A hunk header bordered the conflict */
356 /* If any of the merges are Changed or Conflict,
357 * then this really is a Conflict or Wiggle.
358 * If not they are just Unchanged, Unmatched,
359 * Extraneous or AlreadyApplied, and so don't
361 * Note that the first/last merges (in_conflict==1)
362 * can be Changed and so much be check separately.
364 if (m
[j
].type
== Changed
)
366 for (j
= i
-1; j
>= 0 && m
[j
].in_conflict
> 1; j
--)
367 if (m
[j
].type
== Changed
|| m
[j
].type
== Conflict
)
369 if (j
>= 0 && m
[j
].type
== Changed
)
371 /* False alarm, no real conflict/wiggle here as
372 * nothing changed. */
375 if (m
[j
].in_conflict
== 1) {
378 m
[j
].in_conflict
= 0;
382 m
[j
++].in_conflict
= 0;
384 if (m
[i
].type
== End
)
387 for (k
= 1; k
< m
[i
].al
; k
++) {
388 if (m
[i
].a
+ k
>= af
.elcnt
)
389 /* FIXME this should be impossible, but
393 if (words
|| ends_line(af
.list
[m
[i
].a
+k
])) {
405 /* Now count the conflicts and wiggles */
406 for (i
= 0; m
[i
].type
!= End
; i
++) {
407 int true_conflict
= 0;
408 if (!m
[i
].in_conflict
)
411 for (j
= i
; m
[j
].type
!= End
&& m
[j
].in_conflict
; j
++) {
412 if (m
[j
].in_conflict
== 2)
415 m
[j
].in_conflict
== 1) {
417 if (!m
[j
+1].in_conflict
)
433 struct ci
make_merger(struct file af
, struct file bf
, struct file cf
,
434 struct csl
*csl1
, struct csl
*csl2
, int words
,
435 int ignore_already
, int show_wiggles
)
437 /* find the wiggles and conflicts between csl1 and csl2
442 int header_checked
= -1;
443 int header_found
= 0;
445 rv
.conflicts
= rv
.wiggles
= rv
.ignored
= 0;
447 for (i
= 0; csl1
[i
].len
; i
++)
450 for (i
= 0; csl2
[i
].len
; i
++)
453 /* maybe a bit of slack at each end */
456 rv
.merger
= xmalloc(sizeof(struct merge
)*l
);
458 a
= b
= c
= c1
= c2
= 0;
462 match1
= (a
>= csl1
[c1
].a
&& b
>= csl1
[c1
].b
); /* c1 doesn't match */
463 match2
= (b
>= csl2
[c2
].a
&& c
>= csl2
[c2
].b
);
465 if (header_checked
!= c2
) {
466 /* Check if there is a hunk header in this range */
469 for (j
= b
; j
< csl2
[c2
].a
+ csl2
[c2
].len
; j
++)
470 if (bf
.list
[j
].start
[0] == '\0') {
479 rv
.merger
[i
].c1
= c1
;
480 rv
.merger
[i
].c2
= c2
;
481 rv
.merger
[i
].in_conflict
= 0;
483 if (!match1
&& match2
) {
484 /* This is either Unmatched or Extraneous - probably both.
485 * If the match2 has a hunk-header Extraneous, it must
486 * align with an end-of-line in 'a', so adjust endpoint
488 int newa
= csl1
[c1
].a
;
489 if (header_found
>= 0) {
491 !ends_line(af
.list
[newa
-1]))
494 if (a
== newa
&& b
== csl1
[c1
].b
)
497 /* some unmatched text */
498 rv
.merger
[i
].type
= Unmatched
;
499 rv
.merger
[i
].al
= newa
- a
;
504 assert(b
< csl1
[c1
].b
);
505 /* some Extraneous text */
506 /* length is min of unmatched on left
507 * and matched on right.
508 * However a hunk-header must be an
509 * Extraneous section by itself, so if this
510 * start with one, the length is 1, and if
511 * there is one in the middle, only take the
512 * text up to there for now.
514 rv
.merger
[i
].type
= Extraneous
;
518 csl2
[c2
].len
- (b
-csl2
[c2
].a
));
519 if (header_found
== b
) {
522 } else if (header_found
> b
&& header_found
< newb
) {
528 rv
.merger
[i
].bl
= newb
- b
;
530 } else if (match1
&& !match2
) {
532 * if 'c' is currently at a suitable cut-point, then
533 * we can look for a triple-cut-point for start.
534 * Also, if csl2[c2].b isn't in a conflict, and is
535 * a suitable cut-point, then we could make a
536 * triple-cut-point for end of a conflict.
539 rv
.merger
[i
].type
= Changed
;
540 rv
.merger
[i
].bl
= min(csl1
[c1
].b
+csl1
[c1
].len
, csl2
[c2
].a
) - b
;
541 rv
.merger
[i
].al
= rv
.merger
[i
].bl
;
542 rv
.merger
[i
].cl
= csl2
[c2
].b
- c
;
543 } else if (match1
&& match2
) {
544 /* Some unchanged text
546 rv
.merger
[i
].type
= Unchanged
;
548 min(csl1
[c1
].len
- (b
-csl1
[c1
].b
),
549 csl2
[c2
].len
- (b
-csl2
[c2
].a
));
550 rv
.merger
[i
].al
= rv
.merger
[i
].cl
=
553 /* must be a conflict.
554 * Move a and c to next match, and b to closest of the two
556 rv
.merger
[i
].type
= Conflict
;
557 rv
.merger
[i
].al
= csl1
[c1
].a
- a
;
558 rv
.merger
[i
].cl
= csl2
[c2
].b
- c
;
559 rv
.merger
[i
].bl
= min(csl1
[c1
].b
, csl2
[c2
].a
) - b
;
560 if (ignore_already
&&
561 check_alreadyapplied(af
, cf
, &rv
.merger
[i
]))
563 else if (rv
.merger
[i
].bl
== 0 &&
565 /* As the 'before' stream is empty, this
566 * could look like Unmatched in the
567 * original, and an insertion in the
568 * diff. Reporting it like that is
569 * probably more useful that as a full
571 * Leave the type for the insertion as
572 * Conflict (not Changed) as there is some
573 * real uncertainty here, but allow the
574 * original to become Unmatched.
578 rv
.merger
[i
].oldtype
= rv
.merger
[i
].type
;
579 a
+= rv
.merger
[i
].al
;
580 b
+= rv
.merger
[i
].bl
;
581 c
+= rv
.merger
[i
].cl
;
584 while (csl1
[c1
].a
+ csl1
[c1
].len
<= a
&& csl1
[c1
].len
)
586 assert(csl1
[c1
].b
+ csl1
[c1
].len
>= b
);
587 while (csl2
[c2
].b
+ csl2
[c2
].len
<= c
&& csl2
[c2
].len
)
589 assert(csl2
[c2
].a
+ csl2
[c2
].len
>= b
);
590 if (csl1
[c1
].len
== 0 && csl2
[c2
].len
== 0 &&
591 a
== csl1
[c1
].a
&& b
== csl1
[c1
].b
&&
592 b
== csl2
[c2
].a
&& c
== csl2
[c2
].b
)
595 rv
.merger
[i
].type
= End
;
596 rv
.merger
[i
].oldtype
= End
;
600 rv
.merger
[i
].c1
= c1
;
601 rv
.merger
[i
].c2
= c2
;
602 rv
.merger
[i
].in_conflict
= 0;
605 /* Now revert any AlreadyApplied that aren't bounded by
606 * Unchanged or Changed.
608 for (i
= 0; rv
.merger
[i
].type
!= End
; i
++) {
609 if (rv
.merger
[i
].type
!= AlreadyApplied
)
611 if (i
> 0 && rv
.merger
[i
-1].type
!= Unchanged
&&
612 rv
.merger
[i
-1].type
!= Changed
)
613 rv
.merger
[i
].type
= Conflict
;
614 if (rv
.merger
[i
+1].type
!= Unchanged
&&
615 rv
.merger
[i
+1].type
!= Changed
&&
616 rv
.merger
[i
+1].type
!= End
)
617 rv
.merger
[i
].type
= Conflict
;
619 rv
.conflicts
= isolate_conflicts(af
, bf
, cf
, csl1
, csl2
, words
,
620 rv
.merger
, show_wiggles
, &rv
.wiggles
);
624 static int printrange(FILE *out
, struct file
*f
, int start
, int len
,
628 while (len
> 0 && start
< f
->elcnt
) {
629 struct elmnt e
= f
->list
[start
];
631 if (e
.start
[e
.plen
-1] == '\n' &&
641 int print_merge(FILE *out
, struct file
*a
, struct file
*b
, struct file
*c
,
642 int words
, struct merge
*merger
,
643 struct merge
*mpos
, int streampos
, int offsetpos
)
648 int offset
= INT_MAX
;
650 for (m
= merger
; m
->type
!= End
; m
++) {
653 printf("[%s: %d-%d,%d-%d,%d-%d%s(%d,%d)]\n",
654 m
->type
==Unmatched
? "Unmatched" :
655 m
->type
==Unchanged
? "Unchanged" :
656 m
->type
==Extraneous
? "Extraneous" :
657 m
->type
==Changed
? "Changed" :
658 m
->type
==AlreadyApplied
? "AlreadyApplied" :
659 m
->type
==Conflict
? "Conflict":"unknown",
663 m
->in_conflict
? " in_conflict" : "",
666 while (m
->in_conflict
) {
667 /* need to print from 'hi' to 'lo' of next
668 * Unchanged which is < it's hi
670 int found_conflict
= 0;
672 if (m
->in_conflict
== 1)
678 if (m
->in_conflict
== 1 && m
->type
== Unchanged
)
679 lineno
+= printrange(out
, a
, m
->a
+m
->lo
, m
->hi
- m
->lo
, offset
- m
->lo
);
684 for (cm
= m
; cm
->in_conflict
; cm
++) {
685 printf("{%s: %d-%d,%d-%d,%d-%d%s(%d,%d)}\n",
686 cm
->type
==Unmatched
?"Unmatched":
687 cm
->type
==Unchanged
?"Unchanged":
688 cm
->type
==Extraneous
?"Extraneous":
689 cm
->type
==Changed
?"Changed":
690 cm
->type
==AlreadyApplied
?"AlreadyApplied":
691 cm
->type
==Conflict
?"Conflict":"unknown",
692 cm
->a
, cm
->a
+cm
->al
-1,
693 cm
->b
, cm
->b
+cm
->bl
-1,
694 cm
->c
, cm
->c
+cm
->cl
-1,
695 cm
->in_conflict
? " in_conflict" : "",
697 if (cm
->in_conflict
== 1 && cm
!= m
)
701 if (m
->in_conflict
== 1 &&
702 m
[1].in_conflict
== 1) {
703 /* Nothing between two conflicts */
708 fputs(words
? "<<<---" : "<<<<<<< found\n", out
);
711 for (cm
= m
; cm
->in_conflict
; cm
++) {
712 if (cm
== mpos
&& streampos
== 0)
714 if (cm
->type
== Conflict
)
716 if (cm
->in_conflict
== 1 && cm
!= m
) {
717 lineno
+= printrange(out
, a
, cm
->a
, cm
->lo
, offset
);
720 lineno
+= printrange(out
, a
, cm
->a
+st1
, cm
->al
-st1
, offset
-st1
);
722 if (cm
== mpos
&& streampos
== 0)
725 if (cm
== mpos
&& streampos
== 0)
727 fputs(words
? "|||" : "||||||| expected\n", out
);
731 for (cm
= m
; cm
->in_conflict
; cm
++) {
732 if (cm
== mpos
&& streampos
== 1)
734 if (cm
->in_conflict
== 1 && cm
!= m
) {
735 lineno
+= printrange(out
, a
, cm
->a
, cm
->lo
, offset
);
738 lineno
+= printrange(out
, b
, cm
->b
+st1
, cm
->bl
-st1
, offset
-st1
);
740 if (cm
== mpos
&& streampos
== 1)
743 if (cm
== mpos
&& streampos
== 1)
745 fputs(words
? "===" : "=======\n", out
);
749 for (cm
= m
; cm
->in_conflict
; cm
++) {
750 if (cm
== mpos
&& streampos
== 2)
752 if (cm
->in_conflict
== 1 && cm
!= m
) {
753 if (cm
->type
== Unchanged
)
754 lineno
+= printrange(out
, a
, cm
->a
, cm
->lo
, offset
);
756 lineno
+= printrange(out
, c
, cm
->c
, cm
->cl
, offset
);
759 if (cm
->type
== Changed
)
760 st1
= 0; /* All of result of change must be printed */
761 lineno
+= printrange(out
, c
, cm
->c
+st1
, cm
->cl
-st1
, offset
-st1
);
763 if (cm
== mpos
&& streampos
== 2)
766 if (cm
== mpos
&& streampos
== 2)
768 if (!found_conflict
) {
769 /* This section was wiggled in successfully,
770 * but full conflict display was requested.
771 * So now print out the wiggled result as well.
773 fputs(words
? "&&&" : "&&&&&&& resolution\n", out
);
777 for (cm
= m
; cm
->in_conflict
; cm
++) {
779 if (cm
->in_conflict
== 1 && cm
!= m
)
785 lineno
+= printrange(out
, a
, cm
->a
+st1
,
786 last
? cm
->lo
: cm
->al
-st1
, offset
-st1
);
791 lineno
+= printrange(out
, c
, cm
->c
,
792 last
? cm
->lo
: cm
->cl
, offset
);
803 fputs(words
? "--->>>" : ">>>>>>> replacement\n", out
);
807 if (m
->in_conflict
== 1 && m
[1].in_conflict
== 0) {
808 /* End of a conflict, no conflict follows */
811 if (m
->type
== Unchanged
)
812 lineno
+= printrange(out
, a
, m
->a
+m
->lo
, m
->hi
-m
->lo
, offset
-m
->lo
);
819 /* there is always some non-conflict after a conflict,
820 * unless we hit the end
826 printf("<<%s: %d-%d,%d-%d,%d-%d%s(%d,%d)>>\n",
827 m
->type
==Unmatched
?"Unmatched":
828 m
->type
==Unchanged
?"Unchanged":
829 m
->type
==Extraneous
?"Extraneous":
830 m
->type
==Changed
?"Changed":
831 m
->type
==AlreadyApplied
?"AlreadyApplied":
832 m
->type
==Conflict
?"Conflict":"unknown",
836 m
->in_conflict
? " in_conflict" : "",
846 lineno
+= printrange(out
, a
, m
->a
, m
->al
, offset
);
851 lineno
+= printrange(out
, c
, m
->c
, m
->cl
, offset
);
863 int save_merge(struct file a
, struct file b
, struct file c
,
864 struct merge
*merger
, char *file
, int backup
)
866 char *replacename
= xmalloc(strlen(file
) + 20);
867 char *orignew
= xmalloc(strlen(file
) + 20);
872 strcpy(replacename
, file
);
873 strcat(replacename
, "XXXXXX");
874 strcpy(orignew
, file
);
875 strcat(orignew
, ".porig");
877 fd
= mkstemp(replacename
);
882 outfile
= fdopen(fd
, "w");
883 lineno
= print_merge(outfile
, &a
, &b
, &c
, 0, merger
,
886 if (backup
&& rename(file
, orignew
) != 0)
888 else if (rename(replacename
, file
) != 0)
894 return err
< 0 ? err
: lineno
;
897 int save_tmp_merge(struct file a
, struct file b
, struct file c
,
898 struct merge
*merger
, char **filep
,
899 struct merge
*mpos
, int streampos
, int offsetpos
)
908 dir
= getenv("TMPDIR");
912 asprintf(&fname
, "%s/wiggle-tmp-XXXXXX", dir
);
916 base
= strrchr(dir
, '/');
921 asprintf(&fname
, "%.*stmp-XXXXXX-%s", (int)(base
-dir
), dir
, base
);
922 suffix
= strlen(base
)+1;
924 fd
= mkstemps(fname
, suffix
);
931 outfile
= fdopen(fd
, "w");
932 lineno
= print_merge(outfile
, &a
, &b
, &c
, 0, merger
,
933 mpos
, streampos
, offsetpos
);