1 /* $OpenBSD: diff3.c,v 1.41 2016/10/18 21:06:52 millert Exp $ */
4 * Copyright (C) Caldera International Inc. 2001-2002.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code and documentation must retain the above
11 * copyright notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed or owned by Caldera
19 * 4. Neither the name of Caldera International, Inc. nor the names of other
20 * contributors may be used to endorse or promote products derived from
21 * this software without specific prior written permission.
23 * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
24 * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
25 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
26 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
27 * IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE FOR ANY DIRECT,
28 * INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
29 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
32 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
33 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34 * POSSIBILITY OF SUCH DAMAGE.
37 * Copyright (c) 1991, 1993
38 * The Regents of the University of California. All rights reserved.
40 * Redistribution and use in source and binary forms, with or without
41 * modification, are permitted provided that the following conditions
43 * 1. Redistributions of source code must retain the above copyright
44 * notice, this list of conditions and the following disclaimer.
45 * 2. Redistributions in binary form must reproduce the above copyright
46 * notice, this list of conditions and the following disclaimer in the
47 * documentation and/or other materials provided with the distribution.
48 * 3. Neither the name of the University nor the names of its contributors
49 * may be used to endorse or promote products derived from this software
50 * without specific prior written permission.
52 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
53 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
54 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
55 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
56 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
57 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
58 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
59 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
60 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
61 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
64 * @(#)diff3.c 8.1 (Berkeley) 6/6/93
67 #include "got_compat.h"
70 #include <sys/queue.h>
81 #include "got_error.h"
82 #include "got_opentemp.h"
83 #include "got_object.h"
88 #include "got_lib_diff.h"
91 #define nitems(_a) (sizeof(_a) / sizeof((_a)[0]))
94 /* diff3 - 3-way differential file comparison */
96 /* diff3 [-ex3EX] d13 d23 f1 f2 f3 [m1 m3]
98 * d13 = diff report on f1 vs f3
99 * d23 = diff report on f2 vs f3
100 * f1, f2, f3 the 3 files
101 * if changes in f1 overlap with changes in f3, m1 and m3 are used
102 * to mark the overlaps; otherwise, the file names f1 and f3 are used
103 * (only for options E and X).
107 * "from" is first in range of changed lines; "to" is last+1
108 * from=to=line after point of insertion for added lines.
121 struct line_range old
;
122 struct line_range
new;
123 struct off_range oldo
;
124 struct off_range newo
;
134 * "de" is used to gather editing scripts. These are later spewed out
135 * in reverse order. Its first element must be all zero, the "new"
136 * component of "de" contains line positions, and "oldo" and "newo"
137 * components contain byte positions.
138 * Array overlap indicates which sections in "de" correspond to lines
139 * that are different in all three files.
145 int cline
[3]; /* # of the last-read line in each file (0-2) */
148 * the latest known correspondence between line numbers of the 3 files
149 * is stored in last[1-3];
152 char f1mark
[PATH_MAX
];
153 char f2mark
[PATH_MAX
];
154 char f3mark
[PATH_MAX
];
162 static const struct got_error
*duplicate(int *, int, struct line_range
*,
163 struct line_range
*, struct diff3_state
*);
164 static const struct got_error
*edit(struct diff
*, int, int *,
165 struct diff3_state
*);
166 static const struct got_error
*getchange(char **, FILE *, struct diff3_state
*);
167 static const struct got_error
*get_line(char **, FILE *, size_t *,
168 struct diff3_state
*);
169 static int number(char **);
170 static const struct got_error
*readin(size_t *, char *, struct diff
**,
171 struct diff3_state
*);
172 static int ed_patch_lines(struct rcs_lines
*, struct rcs_lines
*);
173 static const struct got_error
*skip(size_t *, int, int, struct diff3_state
*);
174 static const struct got_error
*edscript(int, struct diff3_state
*);
175 static const struct got_error
*merge(size_t, size_t, struct diff3_state
*);
176 static const struct got_error
*prange(struct line_range
*,
177 struct diff3_state
*);
178 static const struct got_error
*repos(int, struct diff3_state
*);
179 static const struct got_error
*increase(struct diff3_state
*);
180 static const struct got_error
*diff3_internal(char *, char *, char *,
181 char *, char *, const char *, const char *, struct diff3_state
*,
182 const char *, const char *, const char *);
184 static const struct got_error
*
185 diff_output(BUF
*diffbuf
, const char *fmt
, ...)
187 const struct got_error
*err
= NULL
;
194 i
= vasprintf(&str
, fmt
, vap
);
197 return got_error_from_errno("vasprintf");
198 err
= buf_append(&newsize
, diffbuf
, str
, strlen(str
));
203 static const struct got_error
*
204 diffreg(BUF
**d
, const char *path1
, const char *path2
,
205 enum got_diff_algorithm diff_algo
)
207 const struct got_error
*err
= NULL
;
208 FILE *f1
= NULL
, *f2
= NULL
, *outfile
= NULL
;
209 char *outpath
= NULL
;
210 struct got_diffreg_result
*diffreg_result
= NULL
;
214 f1
= fopen(path1
, "re");
216 err
= got_error_from_errno2("fopen", path1
);
219 f2
= fopen(path2
, "re");
221 err
= got_error_from_errno2("fopen", path2
);
225 err
= got_opentemp_named(&outpath
, &outfile
,
226 GOT_TMPDIR_STR
"/got-diffreg", "");
230 err
= got_diffreg(&diffreg_result
, f1
, f2
, diff_algo
, 0, 0);
234 if (diffreg_result
) {
235 struct diff_result
*diff_result
= diffreg_result
->result
;
236 int atomizer_flags
= (diff_result
->left
->atomizer_flags
|
237 diff_result
->right
->atomizer_flags
);
238 if ((atomizer_flags
& DIFF_ATOMIZER_FOUND_BINARY_DATA
)) {
239 err
= got_error(GOT_ERR_FILE_BINARY
);
244 err
= got_diffreg_output(NULL
, NULL
, diffreg_result
, 1, 1, "", "",
245 GOT_DIFF_OUTPUT_PLAIN
, 0, outfile
);
249 if (fflush(outfile
) != 0) {
250 err
= got_error_from_errno2("fflush", outpath
);
253 if (fseek(outfile
, 0L, SEEK_SET
) == -1) {
254 err
= got_ferror(outfile
, GOT_ERR_IO
);
258 err
= buf_load(d
, outfile
);
261 if (unlink(outpath
) == -1 && err
== NULL
)
262 err
= got_error_from_errno2("unlink", outpath
);
265 if (outfile
&& fclose(outfile
) == EOF
&& err
== NULL
)
266 err
= got_error_from_errno("fclose");
267 if (f1
&& fclose(f1
) == EOF
&& err
== NULL
)
268 err
= got_error_from_errno("fclose");
269 if (f2
&& fclose(f2
) == EOF
&& err
== NULL
)
270 err
= got_error_from_errno("fclose");
277 const struct got_error
*
278 got_merge_diff3(int *overlapcnt
, int outfd
, FILE *f1
, FILE *f2
,
279 FILE *f3
, const char *label1
, const char *label2
, const char *label3
,
280 enum got_diff_algorithm diff_algo
)
282 const struct got_error
*err
= NULL
;
283 char *dp13
, *dp23
, *path1
, *path2
, *path3
;
284 BUF
*b1
, *b2
, *b3
, *d1
, *d2
, *diffb
;
285 u_char
*data
, *patch
;
286 size_t dlen
, plen
, i
;
287 struct diff3_state
*d3s
;
291 d3s
= calloc(1, sizeof(*d3s
));
293 return got_error_from_errno("calloc");
295 b1
= b2
= b3
= d1
= d2
= diffb
= NULL
;
296 dp13
= dp23
= path1
= path2
= path3
= NULL
;
299 err
= buf_load(&b1
, f1
);
302 err
= buf_load(&b2
, f2
);
305 err
= buf_load(&b3
, f3
);
309 err
= buf_alloc(&diffb
, 128);
313 if (asprintf(&path1
, GOT_TMPDIR_STR
"/got-diff1.XXXXXXXX") == -1) {
314 err
= got_error_from_errno("asprintf");
317 if (asprintf(&path2
, GOT_TMPDIR_STR
"/got-diff2.XXXXXXXX") == -1) {
318 err
= got_error_from_errno("asprintf");
321 if (asprintf(&path3
, GOT_TMPDIR_STR
"/got-diff3.XXXXXXXX") == -1) {
322 err
= got_error_from_errno("asprintf");
326 err
= buf_write_stmp(b1
, path1
);
329 err
= buf_write_stmp(b2
, path2
);
332 err
= buf_write_stmp(b3
, path3
);
339 err
= diffreg(&d1
, path1
, path3
, diff_algo
);
346 err
= diffreg(&d2
, path2
, path3
, diff_algo
);
353 if (asprintf(&dp13
, GOT_TMPDIR_STR
"/got-d13.XXXXXXXXXX") == -1) {
354 err
= got_error_from_errno("asprintf");
357 err
= buf_write_stmp(d1
, dp13
);
364 if (asprintf(&dp23
, GOT_TMPDIR_STR
"/got-d23.XXXXXXXXXX") == -1) {
365 err
= got_error_from_errno("asprintf");
368 err
= buf_write_stmp(d2
, dp23
);
375 d3s
->diffbuf
= diffb
;
376 err
= diff3_internal(dp13
, dp23
, path1
, path2
, path3
,
377 label1
, label3
, d3s
, label1
, label2
, label3
);
384 plen
= buf_len(diffb
);
385 patch
= buf_release(diffb
);
387 data
= buf_release(b1
);
389 diffb
= rcs_patchfile(data
, dlen
, patch
, plen
, ed_patch_lines
);
396 if (unlink(path1
) == -1 && err
== NULL
)
397 err
= got_error_from_errno2("unlink", path1
);
398 if (unlink(path2
) == -1 && err
== NULL
)
399 err
= got_error_from_errno2("unlink", path2
);
400 if (unlink(path3
) == -1 && err
== NULL
)
401 err
= got_error_from_errno2("unlink", path3
);
402 if (unlink(dp13
) == -1 && err
== NULL
)
403 err
= got_error_from_errno2("unlink", dp13
);
404 if (unlink(dp23
) == -1 && err
== NULL
)
405 err
= got_error_from_errno2("unlink", dp23
);
415 for (i
= 0; i
< nitems(d3s
->fp
); i
++) {
416 if (d3s
->fp
[i
] && fclose(d3s
->fp
[i
]) == EOF
&& err
== NULL
)
417 err
= got_error_from_errno("fclose");
419 if (err
== NULL
&& diffb
) {
420 if (buf_write_fd(diffb
, outfd
) < 0)
421 err
= got_error_from_errno("buf_write_fd");
422 *overlapcnt
= d3s
->overlapcnt
;
429 static const struct got_error
*
430 diff3_internal(char *dp13
, char *dp23
, char *path1
, char *path2
, char *path3
,
431 const char *fmark
, const char *rmark
, struct diff3_state
*d3s
,
432 const char *label1
, const char *label2
, const char *label3
)
434 const struct got_error
*err
= NULL
;
438 i
= snprintf(d3s
->f1mark
, sizeof(d3s
->f1mark
),
439 "%s%s%s", GOT_DIFF_CONFLICT_MARKER_BEGIN
,
440 label1
? " " : "", label1
? label1
: "");
441 if (i
< 0 || i
>= (int)sizeof(d3s
->f1mark
))
442 return got_error(GOT_ERR_NO_SPACE
);
444 i
= snprintf(d3s
->f2mark
, sizeof(d3s
->f2mark
),
445 "%s%s%s", GOT_DIFF_CONFLICT_MARKER_ORIG
,
446 label2
? " " : "", label2
? label2
: "");
447 if (i
< 0 || i
>= (int)sizeof(d3s
->f2mark
))
448 return got_error(GOT_ERR_NO_SPACE
);
450 i
= snprintf(d3s
->f3mark
, sizeof(d3s
->f3mark
),
451 "%s%s%s", GOT_DIFF_CONFLICT_MARKER_END
,
452 label3
? " " : "", label3
? label3
: "");
453 if (i
< 0 || i
>= (int)sizeof(d3s
->f3mark
))
454 return got_error(GOT_ERR_NO_SPACE
);
460 err
= readin(&m
, dp13
, &d3s
->d13
, d3s
);
463 err
= readin(&n
, dp23
, &d3s
->d23
, d3s
);
467 if ((d3s
->fp
[0] = fopen(path1
, "re")) == NULL
)
468 return got_error_from_errno2("fopen", path1
);
469 if ((d3s
->fp
[1] = fopen(path2
, "re")) == NULL
)
470 return got_error_from_errno2("fopen", path2
);
471 if ((d3s
->fp
[2] = fopen(path3
, "re")) == NULL
)
472 return got_error_from_errno2("fopen", path3
);
474 return merge(m
, n
, d3s
);
478 ed_patch_lines(struct rcs_lines
*dlines
, struct rcs_lines
*plines
)
481 struct rcs_line
*sort
, *lp
, *dlp
, *ndlp
, *insert_after
;
482 int start
, end
, i
, lineno
;
485 dlp
= TAILQ_FIRST(&(dlines
->l_lines
));
486 lp
= TAILQ_FIRST(&(plines
->l_lines
));
489 for (lp
= TAILQ_NEXT(lp
, l_list
); lp
!= NULL
;
490 lp
= TAILQ_NEXT(lp
, l_list
)) {
491 /* Skip blank lines */
495 /* NUL-terminate line buffer for strtol() safety. */
496 tmp
= lp
->l_line
[lp
->l_len
- 1];
497 lp
->l_line
[lp
->l_len
- 1] = '\0';
499 /* len - 1 is NUL terminator so we use len - 2 for 'op' */
500 op
= lp
->l_line
[lp
->l_len
- 2];
501 start
= (int)strtol(lp
->l_line
, &ep
, 10);
503 /* Restore the last byte of the buffer */
504 lp
->l_line
[lp
->l_len
- 1] = tmp
;
507 if (start
> dlines
->l_nblines
||
508 start
< 0 || *ep
!= 'a')
510 } else if (op
== 'c') {
511 if (start
> dlines
->l_nblines
||
512 start
< 0 || (*ep
!= ',' && *ep
!= 'c'))
517 end
= (int)strtol(ep
, &ep
, 10);
518 if (end
< 0 || *ep
!= 'c')
529 if (dlp
->l_lineno
== start
)
531 if (dlp
->l_lineno
> start
) {
532 dlp
= TAILQ_PREV(dlp
, tqh
, l_list
);
533 } else if (dlp
->l_lineno
< start
) {
534 ndlp
= TAILQ_NEXT(dlp
, l_list
);
535 if (ndlp
->l_lineno
> start
)
546 insert_after
= TAILQ_PREV(dlp
, tqh
, l_list
);
547 for (i
= 0; i
<= (end
- start
); i
++) {
548 ndlp
= TAILQ_NEXT(dlp
, l_list
);
549 TAILQ_REMOVE(&(dlines
->l_lines
), dlp
, l_list
);
555 if (op
== 'a' || op
== 'c') {
558 lp
= TAILQ_NEXT(lp
, l_list
);
562 if (lp
->l_len
== 2 &&
563 lp
->l_line
[0] == '.' &&
564 lp
->l_line
[1] == '\n')
567 if (lp
->l_line
[0] == ':') {
571 TAILQ_REMOVE(&(plines
->l_lines
), lp
, l_list
);
572 TAILQ_INSERT_AFTER(&(dlines
->l_lines
), dlp
,
576 lp
->l_lineno
= start
;
582 * always resort lines as the markers might be put at the
583 * same line as we first started editing.
586 TAILQ_FOREACH(sort
, &(dlines
->l_lines
), l_list
)
587 sort
->l_lineno
= lineno
++;
588 dlines
->l_nblines
= lineno
- 1;
595 * Pick up the line numbers of all changes from one change file.
596 * (This puts the numbers in a vector, which is not strictly necessary,
597 * since the vector is processed in one sequential pass.
598 * The vector could be optimized out of existence)
600 static const struct got_error
*
601 readin(size_t *n
, char *name
, struct diff
**dd
, struct diff3_state
*d3s
)
603 const struct got_error
*err
= NULL
;
611 f
= fopen(name
, "re");
613 return got_error_from_errno2("fopen", name
);
614 err
= getchange(&p
, f
, d3s
);
617 for (i
= 0; p
; i
++) {
618 if (i
>= d3s
->szchanges
- 1) {
640 (*dd
)[i
].old
.from
= a
;
642 (*dd
)[i
].new.from
= c
;
645 err
= getchange(&p
, f
, d3s
);
651 (*dd
)[i
].old
.from
= (*dd
)[i
- 1].old
.to
;
652 (*dd
)[i
].new.from
= (*dd
)[i
- 1].new.to
;
655 if (fclose(f
) == EOF
&& err
== NULL
)
656 err
= got_error_from_errno("fclose");
668 while (isdigit((unsigned char)(**lc
)))
669 nn
= nn
*10 + *(*lc
)++ - '0';
674 static const struct got_error
*
675 getchange(char **line
, FILE *b
, struct diff3_state
*d3s
)
677 const struct got_error
*err
= NULL
;
681 if (*line
&& isdigit((unsigned char)(*line
)[0]))
683 err
= get_line(line
, b
, NULL
, d3s
);
691 static const struct got_error
*
692 get_line(char **ret
, FILE *b
, size_t *n
, struct diff3_state
*d3s
)
694 const struct got_error
*err
= NULL
;
704 len
= getline(&cp
, &size
, b
);
707 err
= got_error_from_errno("getline");
711 if (cp
[len
- 1] != '\n') {
713 if (len
+ 1 > size
) {
714 new = realloc(cp
, len
+ 1);
716 err
= got_error_from_errno("realloc");
726 *ret
= d3s
->buf
= cp
;
735 static const struct got_error
*
736 merge(size_t m1
, size_t m2
, struct diff3_state
*d3s
)
738 const struct got_error
*err
= NULL
;
739 struct diff
*d1
, *d2
;
746 t1
= (d1
< d3s
->d13
+ m1
);
747 t2
= (d2
< d3s
->d23
+ m2
);
751 /* first file is different from others */
752 if (!t2
|| (t1
&& d1
->new.to
< d2
->new.from
)) {
753 /* stuff peculiar to 1st file */
758 /* second file is different from others */
759 if (!t1
|| (t2
&& d2
->new.to
< d1
->new.from
)) {
765 * Merge overlapping changes in first file
766 * this happens after extension (see below).
768 if (d1
+ 1 < d3s
->d13
+ m1
&& d1
->new.to
>= d1
[1].new.from
) {
769 d1
[1].old
.from
= d1
->old
.from
;
770 d1
[1].new.from
= d1
->new.from
;
775 /* merge overlapping changes in second */
776 if (d2
+ 1 < d3s
->d23
+ m2
&& d2
->new.to
>= d2
[1].new.from
) {
777 d2
[1].old
.from
= d2
->old
.from
;
778 d2
[1].new.from
= d2
->new.from
;
782 /* stuff peculiar to third file or different in all */
783 if (d1
->new.from
== d2
->new.from
&& d1
->new.to
== d2
->new.to
) {
784 err
= duplicate(&dpl
, j
, &d1
->old
, &d2
->old
, d3s
);
789 * dpl = 0 means all files differ
790 * dpl = 1 means files 1 and 2 identical
792 err
= edit(d1
, dpl
, &j
, d3s
);
801 * Overlapping changes from file 1 and 2; extend changes
802 * appropriately to make them coincide.
804 if (d1
->new.from
< d2
->new.from
) {
805 d2
->old
.from
-= d2
->new.from
- d1
->new.from
;
806 d2
->new.from
= d1
->new.from
;
807 } else if (d2
->new.from
< d1
->new.from
) {
808 d1
->old
.from
-= d1
->new.from
- d2
->new.from
;
809 d1
->new.from
= d2
->new.from
;
811 if (d1
->new.to
> d2
->new.to
) {
812 d2
->old
.to
+= d1
->new.to
- d2
->new.to
;
813 d2
->new.to
= d1
->new.to
;
814 } else if (d2
->new.to
> d1
->new.to
) {
815 d1
->old
.to
+= d2
->new.to
- d1
->new.to
;
816 d1
->new.to
= d2
->new.to
;
820 return (edscript(j
, d3s
));
824 * print the range of line numbers, rold.from thru rold.to, as n1,n2 or n1
826 static const struct got_error
*
827 prange(struct line_range
*rold
, struct diff3_state
*d3s
)
829 const struct got_error
*err
= NULL
;
831 if (rold
->to
<= rold
->from
) {
832 err
= diff_output(d3s
->diffbuf
, "%da\n", rold
->from
- 1);
836 err
= diff_output(d3s
->diffbuf
, "%d", rold
->from
);
839 if (rold
->to
> rold
->from
+ 1) {
840 err
= diff_output(d3s
->diffbuf
, ",%d", rold
->to
- 1);
844 err
= diff_output(d3s
->diffbuf
, "c\n");
853 * Skip to just before line number from in file "i".
854 * Return the number of bytes skipped in *nskipped.
856 static const struct got_error
*
857 skip(size_t *nskipped
, int i
, int from
, struct diff3_state
*d3s
)
859 const struct got_error
*err
= NULL
;
864 for (n
= 0; d3s
->cline
[i
] < from
- 1; n
+= len
) {
865 err
= get_line(&line
, d3s
->fp
[i
], &len
, d3s
);
875 * Set *dpl to 1 or 0 according as the old range (in file 1) contains exactly
876 * the same data as the new range (in file 2).
878 * If this change could overlap, remember start/end offsets in file 2 so we
879 * can write out the original lines of text if a merge conflict occurs.
881 static const struct got_error
*
882 duplicate(int *dpl
, int j
, struct line_range
*r1
, struct line_range
*r2
,
883 struct diff3_state
*d3s
)
885 const struct got_error
*err
= NULL
;
894 if (r1
->to
- r1
->from
!= r2
->to
- r2
->from
)
897 err
= skip(&nskipped
, 0, r1
->from
, d3s
);
900 err
= skip(&nskipped
, 1, r2
->from
, d3s
);
904 off
= ftello(d3s
->fp
[1]);
906 return got_error_from_errno("ftello");
907 d3s
->de
[j
+ 1].oldo
.from
= off
; /* original lines start here */
910 for (nline
= 0; nline
< r1
->to
- r1
->from
; nline
++) {
912 c
= getc(d3s
->fp
[0]);
913 d
= getc(d3s
->fp
[1]);
914 if (c
== EOF
&& d
== EOF
)
917 return got_ferror(d3s
->fp
[0], GOT_ERR_EOF
);
919 return got_ferror(d3s
->fp
[1], GOT_ERR_EOF
);
922 long orig_line_len
= nchar
;
924 d
= getc(d3s
->fp
[1]);
929 if (orig_line_len
> nchar
&&
930 fseek(d3s
->fp
[1], -(orig_line_len
- nchar
),
932 return got_ferror(d3s
->fp
[1],
934 /* original lines end here */
935 d3s
->de
[j
+ 1].oldo
.to
= off
+ orig_line_len
;
936 err
= repos(nchar
, d3s
);
944 /* original lines end here */
945 d3s
->de
[j
+ 1].oldo
.to
= off
+ nchar
;
947 err
= repos(nchar
, d3s
);
954 static const struct got_error
*
955 repos(int nchar
, struct diff3_state
*d3s
)
959 for (i
= 0; i
< 2; i
++) {
960 if (fseek(d3s
->fp
[i
], (long)-nchar
, SEEK_CUR
) == -1)
961 return got_ferror(d3s
->fp
[i
], GOT_ERR_IO
);
968 * collect an editing script for later regurgitation
970 static const struct got_error
*
971 edit(struct diff
*diff
, int fdup
, int *j
, struct diff3_state
*d3s
)
973 const struct got_error
*err
= NULL
;
976 if (((fdup
+ 1) & 3) == 0)
979 d3s
->overlap
[*j
] = !fdup
;
982 d3s
->de
[*j
].old
.from
= diff
->old
.from
;
983 d3s
->de
[*j
].old
.to
= diff
->old
.to
;
985 err
= skip(&nskipped
, 2, diff
->new.from
, d3s
);
988 d3s
->de
[*j
].newo
.from
= d3s
->de
[*j
- 1].newo
.to
+ nskipped
;
990 err
= skip(&nskipped
, 2, diff
->new.to
, d3s
);
993 d3s
->de
[*j
].newo
.to
= d3s
->de
[*j
].newo
.from
+ nskipped
;
998 static const struct got_error
*
999 edscript(int n
, struct diff3_state
*d3s
)
1001 const struct got_error
*err
= NULL
;
1004 size_t linesize
= 0;
1005 ssize_t linelen
= 0, k
;
1007 for (; n
> 0; n
--) {
1008 if (!d3s
->overlap
[n
]) {
1009 err
= prange(&d3s
->de
[n
].old
, d3s
);
1012 } else if (d3s
->de
[n
].oldo
.from
< d3s
->de
[n
].oldo
.to
) {
1013 /* Output a block of 3-way diff base file content. */
1014 err
= diff_output(d3s
->diffbuf
, "%da\n:%s\n",
1015 d3s
->de
[n
].old
.to
- 1, d3s
->f2mark
);
1018 if (fseeko(d3s
->fp
[1], d3s
->de
[n
].oldo
.from
, SEEK_SET
)
1020 return got_error_from_errno("fseeko");
1021 len
= (d3s
->de
[n
].oldo
.to
- d3s
->de
[n
].oldo
.from
);
1022 for (k
= 0; k
< (ssize_t
)len
; k
+= linelen
) {
1023 linelen
= getline(&line
, &linesize
, d3s
->fp
[1]);
1024 if (linelen
== -1) {
1025 if (feof(d3s
->fp
[1]))
1027 err
= got_ferror(d3s
->fp
[1],
1031 err
= diff_output(d3s
->diffbuf
, ":%s", line
);
1035 err
= diff_output(d3s
->diffbuf
, "%s%s\n",
1036 linelen
> 0 && line
[linelen
] == '\n' ? ":" : "",
1037 GOT_DIFF_CONFLICT_MARKER_SEP
);
1041 err
= diff_output(d3s
->diffbuf
, "%da\n:%s\n",
1042 d3s
->de
[n
].old
.to
-1, GOT_DIFF_CONFLICT_MARKER_SEP
);
1046 if (fseeko(d3s
->fp
[2], d3s
->de
[n
].newo
.from
, SEEK_SET
)
1048 err
= got_error_from_errno("fseek");
1051 len
= (d3s
->de
[n
].newo
.to
- d3s
->de
[n
].newo
.from
);
1052 for (k
= 0; k
< (ssize_t
)len
; k
+= linelen
) {
1053 linelen
= getline(&line
, &linesize
, d3s
->fp
[2]);
1054 if (linelen
== -1) {
1055 if (feof(d3s
->fp
[2]))
1057 err
= got_ferror(d3s
->fp
[2], GOT_ERR_IO
);
1060 err
= diff_output(d3s
->diffbuf
, ":%s", line
);
1065 if (!d3s
->overlap
[n
]) {
1066 err
= diff_output(d3s
->diffbuf
, ".\n");
1070 err
= diff_output(d3s
->diffbuf
, "%s%s\n.\n",
1071 linelen
> 0 && line
[linelen
] == '\n' ? ":" : "",
1075 err
= diff_output(d3s
->diffbuf
, "%da\n:%s\n.\n",
1076 d3s
->de
[n
].old
.from
- 1, d3s
->f1mark
);
1086 static const struct got_error
*
1087 increase(struct diff3_state
*d3s
)
1093 /* are the memset(3) calls needed? */
1094 newsz
= d3s
->szchanges
== 0 ? 64 : 2 * d3s
->szchanges
;
1095 incr
= newsz
- d3s
->szchanges
;
1097 d
= reallocarray(d3s
->d13
, newsz
, sizeof(*d3s
->d13
));
1099 return got_error_from_errno("reallocarray");
1101 memset(d3s
->d13
+ d3s
->szchanges
, 0, incr
* sizeof(*d3s
->d13
));
1103 d
= reallocarray(d3s
->d23
, newsz
, sizeof(*d3s
->d23
));
1105 return got_error_from_errno("reallocarray");
1107 memset(d3s
->d23
+ d3s
->szchanges
, 0, incr
* sizeof(*d3s
->d23
));
1109 d
= reallocarray(d3s
->de
, newsz
, sizeof(*d3s
->de
));
1111 return got_error_from_errno("reallocarray");
1113 memset(d3s
->de
+ d3s
->szchanges
, 0, incr
* sizeof(*d3s
->de
));
1115 s
= reallocarray(d3s
->overlap
, newsz
, sizeof(*d3s
->overlap
));
1117 return got_error_from_errno("reallocarray");
1119 memset(d3s
->overlap
+ d3s
->szchanges
, 0, incr
* sizeof(*d3s
->overlap
));
1120 d3s
->szchanges
= newsz
;