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
78 #include "got_error.h"
79 #include "got_opentemp.h"
80 #include "got_object.h"
84 #include "got_lib_diff.h"
87 #define nitems(_a) (sizeof(_a) / sizeof((_a)[0]))
90 /* diff3 - 3-way differential file comparison */
92 /* diff3 [-ex3EX] d13 d23 f1 f2 f3 [m1 m3]
94 * d13 = diff report on f1 vs f3
95 * d23 = diff report on f2 vs f3
96 * f1, f2, f3 the 3 files
97 * if changes in f1 overlap with changes in f3, m1 and m3 are used
98 * to mark the overlaps; otherwise, the file names f1 and f3 are used
99 * (only for options E and X).
103 * "from" is first in range of changed lines; "to" is last+1
104 * from=to=line after point of insertion for added lines.
117 struct line_range old
;
118 struct line_range
new;
119 struct off_range oldo
;
120 struct off_range newo
;
130 * "de" is used to gather editing scripts. These are later spewed out
131 * in reverse order. Its first element must be all zero, the "new"
132 * component of "de" contains line positions, and "oldo" and "newo"
133 * components contain byte positions.
134 * Array overlap indicates which sections in "de" correspond to lines
135 * that are different in all three files.
141 int cline
[3]; /* # of the last-read line in each file (0-2) */
144 * the latest known correspondence between line numbers of the 3 files
145 * is stored in last[1-3];
148 char f1mark
[PATH_MAX
];
149 char f2mark
[PATH_MAX
];
150 char f3mark
[PATH_MAX
];
158 static const struct got_error
*duplicate(int *, int, struct line_range
*,
159 struct line_range
*, struct diff3_state
*);
160 static const struct got_error
*edit(struct diff
*, int, int *,
161 struct diff3_state
*);
162 static const struct got_error
*getchange(char **, FILE *, struct diff3_state
*);
163 static const struct got_error
*get_line(char **, FILE *, size_t *,
164 struct diff3_state
*);
165 static int number(char **);
166 static const struct got_error
*readin(size_t *, char *, struct diff
**,
167 struct diff3_state
*);
168 static int ed_patch_lines(struct rcs_lines
*, struct rcs_lines
*);
169 static const struct got_error
*skip(size_t *, int, int, struct diff3_state
*);
170 static const struct got_error
*edscript(int, struct diff3_state
*);
171 static const struct got_error
*merge(size_t, size_t, struct diff3_state
*);
172 static const struct got_error
*prange(struct line_range
*, struct diff3_state
*);
173 static const struct got_error
*repos(int, struct diff3_state
*);
174 static const struct got_error
*increase(struct diff3_state
*);
175 static const struct got_error
*diff3_internal(char *, char *, char *,
176 char *, char *, const char *, const char *, struct diff3_state
*,
177 const char *, const char *, const char *);
179 static const struct got_error
*
180 diff_output(BUF
*diffbuf
, const char *fmt
, ...)
182 const struct got_error
*err
= NULL
;
189 i
= vasprintf(&str
, fmt
, vap
);
192 return got_error_from_errno("vasprintf");
193 err
= buf_append(&newsize
, diffbuf
, str
, strlen(str
));
198 static const struct got_error
*
199 diffreg(BUF
**d
, const char *path1
, const char *path2
,
200 enum got_diff_algorithm diff_algo
)
202 const struct got_error
*err
= NULL
;
203 FILE *f1
= NULL
, *f2
= NULL
, *outfile
= NULL
;
204 char *outpath
= NULL
;
205 struct got_diffreg_result
*diffreg_result
= NULL
;
209 f1
= fopen(path1
, "r");
211 err
= got_error_from_errno2("fopen", path1
);
214 f2
= fopen(path2
, "r");
216 err
= got_error_from_errno2("fopen", path2
);
220 err
= got_opentemp_named(&outpath
, &outfile
,
221 GOT_TMPDIR_STR
"/got-diffreg");
225 err
= got_diffreg(&diffreg_result
, f1
, f2
, diff_algo
, 0, 1);
229 err
= got_diffreg_output(NULL
, NULL
, diffreg_result
, 1, 1, "", "",
230 GOT_DIFF_OUTPUT_EDSCRIPT
, 0, outfile
);
234 if (fflush(outfile
) != 0) {
235 err
= got_error_from_errno2("fflush", outpath
);
238 if (fseek(outfile
, 0L, SEEK_SET
) == -1) {
239 err
= got_ferror(outfile
, GOT_ERR_IO
);
243 err
= buf_load(d
, outfile
);
246 if (unlink(outpath
) == -1 && err
== NULL
)
247 err
= got_error_from_errno2("unlink", outpath
);
250 if (outfile
&& fclose(outfile
) == EOF
&& err
== NULL
)
251 err
= got_error_from_errno("fclose");
252 if (f1
&& fclose(f1
) == EOF
&& err
== NULL
)
253 err
= got_error_from_errno("fclose");
254 if (f2
&& fclose(f2
) == EOF
&& err
== NULL
)
255 err
= got_error_from_errno("fclose");
262 const struct got_error
*
263 got_merge_diff3(int *overlapcnt
, int outfd
, FILE *f1
, FILE *f2
,
264 FILE *f3
, const char *label1
, const char *label2
, const char *label3
,
265 enum got_diff_algorithm diff_algo
)
267 const struct got_error
*err
= NULL
;
268 char *dp13
, *dp23
, *path1
, *path2
, *path3
;
269 BUF
*b1
, *b2
, *b3
, *d1
, *d2
, *diffb
;
270 u_char
*data
, *patch
;
271 size_t dlen
, plen
, i
;
272 struct diff3_state
*d3s
;
276 d3s
= calloc(1, sizeof(*d3s
));
278 return got_error_from_errno("calloc");
280 b1
= b2
= b3
= d1
= d2
= diffb
= NULL
;
281 dp13
= dp23
= path1
= path2
= path3
= NULL
;
284 err
= buf_load(&b1
, f1
);
287 err
= buf_load(&b2
, f2
);
290 err
= buf_load(&b3
, f3
);
294 err
= buf_alloc(&diffb
, 128);
298 if (asprintf(&path1
, GOT_TMPDIR_STR
"/got-diff1.XXXXXXXX") == -1) {
299 err
= got_error_from_errno("asprintf");
302 if (asprintf(&path2
, GOT_TMPDIR_STR
"/got-diff2.XXXXXXXX") == -1) {
303 err
= got_error_from_errno("asprintf");
306 if (asprintf(&path3
, GOT_TMPDIR_STR
"/got-diff3.XXXXXXXX") == -1) {
307 err
= got_error_from_errno("asprintf");
311 err
= buf_write_stmp(b1
, path1
);
314 err
= buf_write_stmp(b2
, path2
);
317 err
= buf_write_stmp(b3
, path3
);
324 err
= diffreg(&d1
, path1
, path3
, diff_algo
);
331 err
= diffreg(&d2
, path2
, path3
, diff_algo
);
338 if (asprintf(&dp13
, GOT_TMPDIR_STR
"/got-d13.XXXXXXXXXX") == -1) {
339 err
= got_error_from_errno("asprintf");
342 err
= buf_write_stmp(d1
, dp13
);
349 if (asprintf(&dp23
, GOT_TMPDIR_STR
"/got-d23.XXXXXXXXXX") == -1) {
350 err
= got_error_from_errno("asprintf");
353 err
= buf_write_stmp(d2
, dp23
);
360 d3s
->diffbuf
= diffb
;
361 err
= diff3_internal(dp13
, dp23
, path1
, path2
, path3
,
362 label1
, label3
, d3s
, label1
, label2
, label3
);
369 plen
= buf_len(diffb
);
370 patch
= buf_release(diffb
);
372 data
= buf_release(b1
);
374 diffb
= rcs_patchfile(data
, dlen
, patch
, plen
, ed_patch_lines
);
381 if (unlink(path1
) == -1 && err
== NULL
)
382 err
= got_error_from_errno2("unlink", path1
);
383 if (unlink(path2
) == -1 && err
== NULL
)
384 err
= got_error_from_errno2("unlink", path2
);
385 if (unlink(path3
) == -1 && err
== NULL
)
386 err
= got_error_from_errno2("unlink", path3
);
387 if (unlink(dp13
) == -1 && err
== NULL
)
388 err
= got_error_from_errno2("unlink", dp13
);
389 if (unlink(dp23
) == -1 && err
== NULL
)
390 err
= got_error_from_errno2("unlink", dp23
);
400 for (i
= 0; i
< nitems(d3s
->fp
); i
++) {
401 if (d3s
->fp
[i
] && fclose(d3s
->fp
[i
]) == EOF
&& err
== NULL
)
402 err
= got_error_from_errno("fclose");
404 if (err
== NULL
&& diffb
) {
405 if (buf_write_fd(diffb
, outfd
) < 0)
406 err
= got_error_from_errno("buf_write_fd");
407 *overlapcnt
= d3s
->overlapcnt
;
414 static const struct got_error
*
415 diff3_internal(char *dp13
, char *dp23
, char *path1
, char *path2
, char *path3
,
416 const char *fmark
, const char *rmark
, struct diff3_state
*d3s
,
417 const char *label1
, const char *label2
, const char *label3
)
419 const struct got_error
*err
= NULL
;
423 i
= snprintf(d3s
->f1mark
, sizeof(d3s
->f1mark
),
424 "%s%s%s", GOT_DIFF_CONFLICT_MARKER_BEGIN
,
425 label1
? " " : "", label1
? label1
: "");
426 if (i
< 0 || i
>= (int)sizeof(d3s
->f1mark
))
427 return got_error(GOT_ERR_NO_SPACE
);
429 i
= snprintf(d3s
->f2mark
, sizeof(d3s
->f2mark
),
430 "%s%s%s", GOT_DIFF_CONFLICT_MARKER_ORIG
,
431 label2
? " " : "", label2
? label2
: "");
432 if (i
< 0 || i
>= (int)sizeof(d3s
->f2mark
))
433 return got_error(GOT_ERR_NO_SPACE
);
435 i
= snprintf(d3s
->f3mark
, sizeof(d3s
->f3mark
),
436 "%s%s%s", GOT_DIFF_CONFLICT_MARKER_END
,
437 label3
? " " : "", label3
? label3
: "");
438 if (i
< 0 || i
>= (int)sizeof(d3s
->f3mark
))
439 return got_error(GOT_ERR_NO_SPACE
);
445 err
= readin(&m
, dp13
, &d3s
->d13
, d3s
);
448 err
= readin(&n
, dp23
, &d3s
->d23
, d3s
);
452 if ((d3s
->fp
[0] = fopen(path1
, "r")) == NULL
)
453 return got_error_from_errno2("fopen", path1
);
454 if ((d3s
->fp
[1] = fopen(path2
, "r")) == NULL
)
455 return got_error_from_errno2("fopen", path2
);
456 if ((d3s
->fp
[2] = fopen(path3
, "r")) == NULL
)
457 return got_error_from_errno2("fopen", path3
);
459 return merge(m
, n
, d3s
);
463 ed_patch_lines(struct rcs_lines
*dlines
, struct rcs_lines
*plines
)
466 struct rcs_line
*sort
, *lp
, *dlp
, *ndlp
, *insert_after
;
467 int start
, end
, i
, lineno
;
470 dlp
= TAILQ_FIRST(&(dlines
->l_lines
));
471 lp
= TAILQ_FIRST(&(plines
->l_lines
));
474 for (lp
= TAILQ_NEXT(lp
, l_list
); lp
!= NULL
;
475 lp
= TAILQ_NEXT(lp
, l_list
)) {
476 /* Skip blank lines */
480 /* NUL-terminate line buffer for strtol() safety. */
481 tmp
= lp
->l_line
[lp
->l_len
- 1];
482 lp
->l_line
[lp
->l_len
- 1] = '\0';
484 /* len - 1 is NUL terminator so we use len - 2 for 'op' */
485 op
= lp
->l_line
[lp
->l_len
- 2];
486 start
= (int)strtol(lp
->l_line
, &ep
, 10);
488 /* Restore the last byte of the buffer */
489 lp
->l_line
[lp
->l_len
- 1] = tmp
;
492 if (start
> dlines
->l_nblines
||
493 start
< 0 || *ep
!= 'a')
495 } else if (op
== 'c') {
496 if (start
> dlines
->l_nblines
||
497 start
< 0 || (*ep
!= ',' && *ep
!= 'c'))
502 end
= (int)strtol(ep
, &ep
, 10);
503 if (end
< 0 || *ep
!= 'c')
514 if (dlp
->l_lineno
== start
)
516 if (dlp
->l_lineno
> start
) {
517 dlp
= TAILQ_PREV(dlp
, tqh
, l_list
);
518 } else if (dlp
->l_lineno
< start
) {
519 ndlp
= TAILQ_NEXT(dlp
, l_list
);
520 if (ndlp
->l_lineno
> start
)
531 insert_after
= TAILQ_PREV(dlp
, tqh
, l_list
);
532 for (i
= 0; i
<= (end
- start
); i
++) {
533 ndlp
= TAILQ_NEXT(dlp
, l_list
);
534 TAILQ_REMOVE(&(dlines
->l_lines
), dlp
, l_list
);
540 if (op
== 'a' || op
== 'c') {
543 lp
= TAILQ_NEXT(lp
, l_list
);
547 if (lp
->l_len
== 2 &&
548 lp
->l_line
[0] == '.' &&
549 lp
->l_line
[1] == '\n')
552 TAILQ_REMOVE(&(plines
->l_lines
), lp
, l_list
);
553 TAILQ_INSERT_AFTER(&(dlines
->l_lines
), dlp
,
557 lp
->l_lineno
= start
;
563 * always resort lines as the markers might be put at the
564 * same line as we first started editing.
567 TAILQ_FOREACH(sort
, &(dlines
->l_lines
), l_list
)
568 sort
->l_lineno
= lineno
++;
569 dlines
->l_nblines
= lineno
- 1;
576 * Pick up the line numbers of all changes from one change file.
577 * (This puts the numbers in a vector, which is not strictly necessary,
578 * since the vector is processed in one sequential pass.
579 * The vector could be optimized out of existence)
581 static const struct got_error
*
582 readin(size_t *n
, char *name
, struct diff
**dd
, struct diff3_state
*d3s
)
584 const struct got_error
*err
= NULL
;
592 f
= fopen(name
, "r");
594 return got_error_from_errno2("fopen", name
);
595 err
= getchange(&p
, f
, d3s
);
598 for (i
= 0; p
; i
++) {
599 if (i
>= d3s
->szchanges
- 1) {
621 (*dd
)[i
].old
.from
= a
;
623 (*dd
)[i
].new.from
= c
;
626 err
= getchange(&p
, f
, d3s
);
632 (*dd
)[i
].old
.from
= (*dd
)[i
- 1].old
.to
;
633 (*dd
)[i
].new.from
= (*dd
)[i
- 1].new.to
;
636 if (fclose(f
) == EOF
&& err
== NULL
)
637 err
= got_error_from_errno("fclose");
649 while (isdigit((unsigned char)(**lc
)))
650 nn
= nn
*10 + *(*lc
)++ - '0';
655 static const struct got_error
*
656 getchange(char **line
, FILE *b
, struct diff3_state
*d3s
)
658 const struct got_error
*err
= NULL
;
662 if (*line
&& isdigit((unsigned char)(*line
)[0]))
664 err
= get_line(line
, b
, NULL
, d3s
);
672 static const struct got_error
*
673 get_line(char **ret
, FILE *b
, size_t *n
, struct diff3_state
*d3s
)
675 const struct got_error
*err
= NULL
;
683 len
= getline(&cp
, &size
, b
);
686 err
= got_error_from_errno("getline");
690 if (cp
[len
- 1] != '\n') {
692 if (len
+ 1 > size
) {
693 new = realloc(cp
, len
+ 1);
695 err
= got_error_from_errno("realloc");
705 *ret
= d3s
->buf
= cp
;
714 static const struct got_error
*
715 merge(size_t m1
, size_t m2
, struct diff3_state
*d3s
)
717 const struct got_error
*err
= NULL
;
718 struct diff
*d1
, *d2
;
725 t1
= (d1
< d3s
->d13
+ m1
);
726 t2
= (d2
< d3s
->d23
+ m2
);
730 /* first file is different from others */
731 if (!t2
|| (t1
&& d1
->new.to
< d2
->new.from
)) {
732 /* stuff peculiar to 1st file */
737 /* second file is different from others */
738 if (!t1
|| (t2
&& d2
->new.to
< d1
->new.from
)) {
744 * Merge overlapping changes in first file
745 * this happens after extension (see below).
747 if (d1
+ 1 < d3s
->d13
+ m1
&& d1
->new.to
>= d1
[1].new.from
) {
748 d1
[1].old
.from
= d1
->old
.from
;
749 d1
[1].new.from
= d1
->new.from
;
754 /* merge overlapping changes in second */
755 if (d2
+ 1 < d3s
->d23
+ m2
&& d2
->new.to
>= d2
[1].new.from
) {
756 d2
[1].old
.from
= d2
->old
.from
;
757 d2
[1].new.from
= d2
->new.from
;
761 /* stuff peculiar to third file or different in all */
762 if (d1
->new.from
== d2
->new.from
&& d1
->new.to
== d2
->new.to
) {
763 err
= duplicate(&dpl
, j
, &d1
->old
, &d2
->old
, d3s
);
768 * dpl = 0 means all files differ
769 * dpl = 1 means files 1 and 2 identical
771 err
= edit(d1
, dpl
, &j
, d3s
);
780 * Overlapping changes from file 1 and 2; extend changes
781 * appropriately to make them coincide.
783 if (d1
->new.from
< d2
->new.from
) {
784 d2
->old
.from
-= d2
->new.from
- d1
->new.from
;
785 d2
->new.from
= d1
->new.from
;
786 } else if (d2
->new.from
< d1
->new.from
) {
787 d1
->old
.from
-= d1
->new.from
- d2
->new.from
;
788 d1
->new.from
= d2
->new.from
;
790 if (d1
->new.to
> d2
->new.to
) {
791 d2
->old
.to
+= d1
->new.to
- d2
->new.to
;
792 d2
->new.to
= d1
->new.to
;
793 } else if (d2
->new.to
> d1
->new.to
) {
794 d1
->old
.to
+= d2
->new.to
- d1
->new.to
;
795 d1
->new.to
= d2
->new.to
;
799 return (edscript(j
, d3s
));
803 * print the range of line numbers, rold.from thru rold.to, as n1,n2 or n1
805 static const struct got_error
*
806 prange(struct line_range
*rold
, struct diff3_state
*d3s
)
808 const struct got_error
*err
= NULL
;
810 if (rold
->to
<= rold
->from
) {
811 err
= diff_output(d3s
->diffbuf
, "%da\n", rold
->from
- 1);
815 err
= diff_output(d3s
->diffbuf
, "%d", rold
->from
);
818 if (rold
->to
> rold
->from
+ 1) {
819 err
= diff_output(d3s
->diffbuf
, ",%d", rold
->to
- 1);
823 err
= diff_output(d3s
->diffbuf
, "c\n");
832 * Skip to just before line number from in file "i".
833 * Return the number of bytes skipped in *nskipped.
835 static const struct got_error
*
836 skip(size_t *nskipped
, int i
, int from
, struct diff3_state
*d3s
)
838 const struct got_error
*err
= NULL
;
843 for (n
= 0; d3s
->cline
[i
] < from
- 1; n
+= len
) {
844 err
= get_line(&line
, d3s
->fp
[i
], &len
, d3s
);
854 * Set *dpl to 1 or 0 according as the old range (in file 1) contains exactly
855 * the same data as the new range (in file 2).
857 * If this change could overlap, remember start/end offsets in file 2 so we
858 * can write out the original lines of text if a merge conflict occurs.
860 static const struct got_error
*
861 duplicate(int *dpl
, int j
, struct line_range
*r1
, struct line_range
*r2
,
862 struct diff3_state
*d3s
)
864 const struct got_error
*err
= NULL
;
873 if (r1
->to
- r1
->from
!= r2
->to
- r2
->from
)
876 err
= skip(&nskipped
, 0, r1
->from
, d3s
);
879 err
= skip(&nskipped
, 1, r2
->from
, d3s
);
883 off
= ftello(d3s
->fp
[1]);
885 return got_error_from_errno("ftello");
886 d3s
->de
[j
+ 1].oldo
.from
= off
; /* original lines start here */
889 for (nline
= 0; nline
< r1
->to
- r1
->from
; nline
++) {
891 c
= getc(d3s
->fp
[0]);
892 d
= getc(d3s
->fp
[1]);
893 if (c
== EOF
&& d
== EOF
)
896 return got_ferror(d3s
->fp
[0], GOT_ERR_EOF
);
898 return got_ferror(d3s
->fp
[1], GOT_ERR_EOF
);
901 long orig_line_len
= nchar
;
903 d
= getc(d3s
->fp
[1]);
908 if (orig_line_len
> nchar
&&
909 fseek(d3s
->fp
[1], -(orig_line_len
- nchar
),
911 return got_ferror(d3s
->fp
[1],
913 /* original lines end here */
914 d3s
->de
[j
+ 1].oldo
.to
= off
+ orig_line_len
;
915 err
= repos(nchar
, d3s
);
922 err
= repos(nchar
, d3s
);
929 static const struct got_error
*
930 repos(int nchar
, struct diff3_state
*d3s
)
934 for (i
= 0; i
< 2; i
++) {
935 if (fseek(d3s
->fp
[i
], (long)-nchar
, SEEK_CUR
) == -1)
936 return got_ferror(d3s
->fp
[i
], GOT_ERR_IO
);
943 * collect an editing script for later regurgitation
945 static const struct got_error
*
946 edit(struct diff
*diff
, int fdup
, int *j
, struct diff3_state
*d3s
)
948 const struct got_error
*err
= NULL
;
951 if (((fdup
+ 1) & 3) == 0)
954 d3s
->overlap
[*j
] = !fdup
;
957 d3s
->de
[*j
].old
.from
= diff
->old
.from
;
958 d3s
->de
[*j
].old
.to
= diff
->old
.to
;
960 err
= skip(&nskipped
, 2, diff
->new.from
, d3s
);
963 d3s
->de
[*j
].newo
.from
= d3s
->de
[*j
- 1].newo
.to
+ nskipped
;
965 err
= skip(&nskipped
, 2, diff
->new.to
, d3s
);
968 d3s
->de
[*j
].newo
.to
= d3s
->de
[*j
].newo
.from
+ nskipped
;
973 static const struct got_error
*
974 edscript(int n
, struct diff3_state
*d3s
)
976 const struct got_error
*err
= NULL
;
978 char block
[BUFSIZ
+1];
981 if (!d3s
->overlap
[n
]) {
982 err
= prange(&d3s
->de
[n
].old
, d3s
);
985 } else if (d3s
->de
[n
].oldo
.from
< d3s
->de
[n
].oldo
.to
) {
986 /* Output a block of 3-way diff base file content. */
987 err
= diff_output(d3s
->diffbuf
, "%da\n%s\n",
988 d3s
->de
[n
].old
.to
- 1, d3s
->f2mark
);
991 if (fseeko(d3s
->fp
[1], d3s
->de
[n
].oldo
.from
, SEEK_SET
)
993 return got_error_from_errno("fseeko");
994 k
= (size_t)(d3s
->de
[n
].oldo
.to
- d3s
->de
[n
].oldo
.from
);
995 for (; k
> 0; k
-= len
) {
997 len
= k
> BUFSIZ
? BUFSIZ
: k
;
998 r
= fread(block
, 1, len
, d3s
->fp
[1]);
1000 if (feof(d3s
->fp
[1]))
1002 return got_ferror(d3s
->fp
[1],
1008 err
= diff_output(d3s
->diffbuf
, "%s", block
);
1012 err
= diff_output(d3s
->diffbuf
, "%s\n",
1013 GOT_DIFF_CONFLICT_MARKER_SEP
);
1017 err
= diff_output(d3s
->diffbuf
, "%da\n%s\n",
1018 d3s
->de
[n
].old
.to
-1, GOT_DIFF_CONFLICT_MARKER_SEP
);
1022 if (fseeko(d3s
->fp
[2], d3s
->de
[n
].newo
.from
, SEEK_SET
)
1024 return got_error_from_errno("fseek");
1025 k
= (size_t)(d3s
->de
[n
].newo
.to
- d3s
->de
[n
].newo
.from
);
1026 for (; k
> 0; k
-= len
) {
1028 len
= k
> BUFSIZ
? BUFSIZ
: k
;
1029 r
= fread(block
, 1, len
, d3s
->fp
[2]);
1031 if (feof(d3s
->fp
[2]))
1033 return got_ferror(d3s
->fp
[2],
1039 err
= diff_output(d3s
->diffbuf
, "%s", block
);
1044 if (!d3s
->overlap
[n
]) {
1045 err
= diff_output(d3s
->diffbuf
, ".\n");
1049 err
= diff_output(d3s
->diffbuf
, "%s\n.\n", d3s
->f3mark
);
1052 err
= diff_output(d3s
->diffbuf
, "%da\n%s\n.\n",
1053 d3s
->de
[n
].old
.from
- 1, d3s
->f1mark
);
1062 static const struct got_error
*
1063 increase(struct diff3_state
*d3s
)
1069 /* are the memset(3) calls needed? */
1070 newsz
= d3s
->szchanges
== 0 ? 64 : 2 * d3s
->szchanges
;
1071 incr
= newsz
- d3s
->szchanges
;
1073 d
= reallocarray(d3s
->d13
, newsz
, sizeof(*d3s
->d13
));
1075 return got_error_from_errno("reallocarray");
1077 memset(d3s
->d13
+ d3s
->szchanges
, 0, incr
* sizeof(*d3s
->d13
));
1079 d
= reallocarray(d3s
->d23
, newsz
, sizeof(*d3s
->d23
));
1081 return got_error_from_errno("reallocarray");
1083 memset(d3s
->d23
+ d3s
->szchanges
, 0, incr
* sizeof(*d3s
->d23
));
1085 d
= reallocarray(d3s
->de
, newsz
, sizeof(*d3s
->de
));
1087 return got_error_from_errno("reallocarray");
1089 memset(d3s
->de
+ d3s
->szchanges
, 0, incr
* sizeof(*d3s
->de
));
1091 s
= reallocarray(d3s
->overlap
, newsz
, sizeof(*d3s
->overlap
));
1093 return got_error_from_errno("reallocarray");
1095 memset(d3s
->overlap
+ d3s
->szchanges
, 0, incr
* sizeof(*d3s
->overlap
));
1096 d3s
->szchanges
= newsz
;