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"
85 #include "got_lib_diff.h"
88 #define nitems(_a) (sizeof(_a) / sizeof((_a)[0]))
91 /* diff3 - 3-way differential file comparison */
93 /* diff3 [-ex3EX] d13 d23 f1 f2 f3 [m1 m3]
95 * d13 = diff report on f1 vs f3
96 * d23 = diff report on f2 vs f3
97 * f1, f2, f3 the 3 files
98 * if changes in f1 overlap with changes in f3, m1 and m3 are used
99 * to mark the overlaps; otherwise, the file names f1 and f3 are used
100 * (only for options E and X).
104 * "from" is first in range of changed lines; "to" is last+1
105 * from=to=line after point of insertion for added lines.
118 struct line_range old
;
119 struct line_range
new;
120 struct off_range oldo
;
121 struct off_range newo
;
131 * "de" is used to gather editing scripts. These are later spewed out
132 * in reverse order. Its first element must be all zero, the "new"
133 * component of "de" contains line positions, and "oldo" and "newo"
134 * components contain byte positions.
135 * Array overlap indicates which sections in "de" correspond to lines
136 * that are different in all three files.
142 int cline
[3]; /* # of the last-read line in each file (0-2) */
145 * the latest known correspondence between line numbers of the 3 files
146 * is stored in last[1-3];
149 char f1mark
[PATH_MAX
];
150 char f2mark
[PATH_MAX
];
151 char f3mark
[PATH_MAX
];
159 static const struct got_error
*duplicate(int *, int, struct line_range
*,
160 struct line_range
*, struct diff3_state
*);
161 static const struct got_error
*edit(struct diff
*, int, int *,
162 struct diff3_state
*);
163 static const struct got_error
*getchange(char **, FILE *, struct diff3_state
*);
164 static const struct got_error
*get_line(char **, FILE *, size_t *,
165 struct diff3_state
*);
166 static int number(char **);
167 static const struct got_error
*readin(size_t *, char *, struct diff
**,
168 struct diff3_state
*);
169 static int ed_patch_lines(struct rcs_lines
*, struct rcs_lines
*);
170 static const struct got_error
*skip(size_t *, int, int, struct diff3_state
*);
171 static const struct got_error
*edscript(int, struct diff3_state
*);
172 static const struct got_error
*merge(size_t, size_t, struct diff3_state
*);
173 static const struct got_error
*prange(struct line_range
*,
174 struct diff3_state
*);
175 static const struct got_error
*repos(int, struct diff3_state
*);
176 static const struct got_error
*increase(struct diff3_state
*);
177 static const struct got_error
*diff3_internal(char *, char *, char *,
178 char *, char *, const char *, const char *, struct diff3_state
*,
179 const char *, const char *, const char *);
181 static const struct got_error
*
182 diff_output(BUF
*diffbuf
, const char *fmt
, ...)
184 const struct got_error
*err
= NULL
;
191 i
= vasprintf(&str
, fmt
, vap
);
194 return got_error_from_errno("vasprintf");
195 err
= buf_append(&newsize
, diffbuf
, str
, strlen(str
));
200 static const struct got_error
*
201 diffreg(BUF
**d
, const char *path1
, const char *path2
,
202 enum got_diff_algorithm diff_algo
)
204 const struct got_error
*err
= NULL
;
205 FILE *f1
= NULL
, *f2
= NULL
, *outfile
= NULL
;
206 char *outpath
= NULL
;
207 struct got_diffreg_result
*diffreg_result
= NULL
;
211 f1
= fopen(path1
, "re");
213 err
= got_error_from_errno2("fopen", path1
);
216 f2
= fopen(path2
, "re");
218 err
= got_error_from_errno2("fopen", path2
);
222 err
= got_opentemp_named(&outpath
, &outfile
,
223 GOT_TMPDIR_STR
"/got-diffreg");
227 err
= got_diffreg(&diffreg_result
, f1
, f2
, diff_algo
, 0, 0);
231 if (diffreg_result
) {
232 struct diff_result
*diff_result
= diffreg_result
->result
;
233 int atomizer_flags
= (diff_result
->left
->atomizer_flags
|
234 diff_result
->right
->atomizer_flags
);
235 if ((atomizer_flags
& DIFF_ATOMIZER_FOUND_BINARY_DATA
)) {
236 err
= got_error(GOT_ERR_FILE_BINARY
);
241 err
= got_diffreg_output(NULL
, NULL
, diffreg_result
, 1, 1, "", "",
242 GOT_DIFF_OUTPUT_EDSCRIPT
, 0, outfile
);
246 if (fflush(outfile
) != 0) {
247 err
= got_error_from_errno2("fflush", outpath
);
250 if (fseek(outfile
, 0L, SEEK_SET
) == -1) {
251 err
= got_ferror(outfile
, GOT_ERR_IO
);
255 err
= buf_load(d
, outfile
);
258 if (unlink(outpath
) == -1 && err
== NULL
)
259 err
= got_error_from_errno2("unlink", outpath
);
262 if (outfile
&& fclose(outfile
) == EOF
&& err
== NULL
)
263 err
= got_error_from_errno("fclose");
264 if (f1
&& fclose(f1
) == EOF
&& err
== NULL
)
265 err
= got_error_from_errno("fclose");
266 if (f2
&& fclose(f2
) == EOF
&& err
== NULL
)
267 err
= got_error_from_errno("fclose");
274 const struct got_error
*
275 got_merge_diff3(int *overlapcnt
, int outfd
, FILE *f1
, FILE *f2
,
276 FILE *f3
, const char *label1
, const char *label2
, const char *label3
,
277 enum got_diff_algorithm diff_algo
)
279 const struct got_error
*err
= NULL
;
280 char *dp13
, *dp23
, *path1
, *path2
, *path3
;
281 BUF
*b1
, *b2
, *b3
, *d1
, *d2
, *diffb
;
282 u_char
*data
, *patch
;
283 size_t dlen
, plen
, i
;
284 struct diff3_state
*d3s
;
288 d3s
= calloc(1, sizeof(*d3s
));
290 return got_error_from_errno("calloc");
292 b1
= b2
= b3
= d1
= d2
= diffb
= NULL
;
293 dp13
= dp23
= path1
= path2
= path3
= NULL
;
296 err
= buf_load(&b1
, f1
);
299 err
= buf_load(&b2
, f2
);
302 err
= buf_load(&b3
, f3
);
306 err
= buf_alloc(&diffb
, 128);
310 if (asprintf(&path1
, GOT_TMPDIR_STR
"/got-diff1.XXXXXXXX") == -1) {
311 err
= got_error_from_errno("asprintf");
314 if (asprintf(&path2
, GOT_TMPDIR_STR
"/got-diff2.XXXXXXXX") == -1) {
315 err
= got_error_from_errno("asprintf");
318 if (asprintf(&path3
, GOT_TMPDIR_STR
"/got-diff3.XXXXXXXX") == -1) {
319 err
= got_error_from_errno("asprintf");
323 err
= buf_write_stmp(b1
, path1
);
326 err
= buf_write_stmp(b2
, path2
);
329 err
= buf_write_stmp(b3
, path3
);
336 err
= diffreg(&d1
, path1
, path3
, diff_algo
);
343 err
= diffreg(&d2
, path2
, path3
, diff_algo
);
350 if (asprintf(&dp13
, GOT_TMPDIR_STR
"/got-d13.XXXXXXXXXX") == -1) {
351 err
= got_error_from_errno("asprintf");
354 err
= buf_write_stmp(d1
, dp13
);
361 if (asprintf(&dp23
, GOT_TMPDIR_STR
"/got-d23.XXXXXXXXXX") == -1) {
362 err
= got_error_from_errno("asprintf");
365 err
= buf_write_stmp(d2
, dp23
);
372 d3s
->diffbuf
= diffb
;
373 err
= diff3_internal(dp13
, dp23
, path1
, path2
, path3
,
374 label1
, label3
, d3s
, label1
, label2
, label3
);
381 plen
= buf_len(diffb
);
382 patch
= buf_release(diffb
);
384 data
= buf_release(b1
);
386 diffb
= rcs_patchfile(data
, dlen
, patch
, plen
, ed_patch_lines
);
393 if (unlink(path1
) == -1 && err
== NULL
)
394 err
= got_error_from_errno2("unlink", path1
);
395 if (unlink(path2
) == -1 && err
== NULL
)
396 err
= got_error_from_errno2("unlink", path2
);
397 if (unlink(path3
) == -1 && err
== NULL
)
398 err
= got_error_from_errno2("unlink", path3
);
399 if (unlink(dp13
) == -1 && err
== NULL
)
400 err
= got_error_from_errno2("unlink", dp13
);
401 if (unlink(dp23
) == -1 && err
== NULL
)
402 err
= got_error_from_errno2("unlink", dp23
);
412 for (i
= 0; i
< nitems(d3s
->fp
); i
++) {
413 if (d3s
->fp
[i
] && fclose(d3s
->fp
[i
]) == EOF
&& err
== NULL
)
414 err
= got_error_from_errno("fclose");
416 if (err
== NULL
&& diffb
) {
417 if (buf_write_fd(diffb
, outfd
) < 0)
418 err
= got_error_from_errno("buf_write_fd");
419 *overlapcnt
= d3s
->overlapcnt
;
426 static const struct got_error
*
427 diff3_internal(char *dp13
, char *dp23
, char *path1
, char *path2
, char *path3
,
428 const char *fmark
, const char *rmark
, struct diff3_state
*d3s
,
429 const char *label1
, const char *label2
, const char *label3
)
431 const struct got_error
*err
= NULL
;
435 i
= snprintf(d3s
->f1mark
, sizeof(d3s
->f1mark
),
436 "%s%s%s", GOT_DIFF_CONFLICT_MARKER_BEGIN
,
437 label1
? " " : "", label1
? label1
: "");
438 if (i
< 0 || i
>= (int)sizeof(d3s
->f1mark
))
439 return got_error(GOT_ERR_NO_SPACE
);
441 i
= snprintf(d3s
->f2mark
, sizeof(d3s
->f2mark
),
442 "%s%s%s", GOT_DIFF_CONFLICT_MARKER_ORIG
,
443 label2
? " " : "", label2
? label2
: "");
444 if (i
< 0 || i
>= (int)sizeof(d3s
->f2mark
))
445 return got_error(GOT_ERR_NO_SPACE
);
447 i
= snprintf(d3s
->f3mark
, sizeof(d3s
->f3mark
),
448 "%s%s%s", GOT_DIFF_CONFLICT_MARKER_END
,
449 label3
? " " : "", label3
? label3
: "");
450 if (i
< 0 || i
>= (int)sizeof(d3s
->f3mark
))
451 return got_error(GOT_ERR_NO_SPACE
);
457 err
= readin(&m
, dp13
, &d3s
->d13
, d3s
);
460 err
= readin(&n
, dp23
, &d3s
->d23
, d3s
);
464 if ((d3s
->fp
[0] = fopen(path1
, "re")) == NULL
)
465 return got_error_from_errno2("fopen", path1
);
466 if ((d3s
->fp
[1] = fopen(path2
, "re")) == NULL
)
467 return got_error_from_errno2("fopen", path2
);
468 if ((d3s
->fp
[2] = fopen(path3
, "re")) == NULL
)
469 return got_error_from_errno2("fopen", path3
);
471 return merge(m
, n
, d3s
);
475 ed_patch_lines(struct rcs_lines
*dlines
, struct rcs_lines
*plines
)
478 struct rcs_line
*sort
, *lp
, *dlp
, *ndlp
, *insert_after
;
479 int start
, end
, i
, lineno
;
482 dlp
= TAILQ_FIRST(&(dlines
->l_lines
));
483 lp
= TAILQ_FIRST(&(plines
->l_lines
));
486 for (lp
= TAILQ_NEXT(lp
, l_list
); lp
!= NULL
;
487 lp
= TAILQ_NEXT(lp
, l_list
)) {
488 /* Skip blank lines */
492 /* NUL-terminate line buffer for strtol() safety. */
493 tmp
= lp
->l_line
[lp
->l_len
- 1];
494 lp
->l_line
[lp
->l_len
- 1] = '\0';
496 /* len - 1 is NUL terminator so we use len - 2 for 'op' */
497 op
= lp
->l_line
[lp
->l_len
- 2];
498 start
= (int)strtol(lp
->l_line
, &ep
, 10);
500 /* Restore the last byte of the buffer */
501 lp
->l_line
[lp
->l_len
- 1] = tmp
;
504 if (start
> dlines
->l_nblines
||
505 start
< 0 || *ep
!= 'a')
507 } else if (op
== 'c') {
508 if (start
> dlines
->l_nblines
||
509 start
< 0 || (*ep
!= ',' && *ep
!= 'c'))
514 end
= (int)strtol(ep
, &ep
, 10);
515 if (end
< 0 || *ep
!= 'c')
526 if (dlp
->l_lineno
== start
)
528 if (dlp
->l_lineno
> start
) {
529 dlp
= TAILQ_PREV(dlp
, tqh
, l_list
);
530 } else if (dlp
->l_lineno
< start
) {
531 ndlp
= TAILQ_NEXT(dlp
, l_list
);
532 if (ndlp
->l_lineno
> start
)
543 insert_after
= TAILQ_PREV(dlp
, tqh
, l_list
);
544 for (i
= 0; i
<= (end
- start
); i
++) {
545 ndlp
= TAILQ_NEXT(dlp
, l_list
);
546 TAILQ_REMOVE(&(dlines
->l_lines
), dlp
, l_list
);
552 if (op
== 'a' || op
== 'c') {
555 lp
= TAILQ_NEXT(lp
, l_list
);
559 if (lp
->l_len
== 2 &&
560 lp
->l_line
[0] == '.' &&
561 lp
->l_line
[1] == '\n')
564 if (lp
->l_line
[0] == ':') {
568 TAILQ_REMOVE(&(plines
->l_lines
), lp
, l_list
);
569 TAILQ_INSERT_AFTER(&(dlines
->l_lines
), dlp
,
573 lp
->l_lineno
= start
;
579 * always resort lines as the markers might be put at the
580 * same line as we first started editing.
583 TAILQ_FOREACH(sort
, &(dlines
->l_lines
), l_list
)
584 sort
->l_lineno
= lineno
++;
585 dlines
->l_nblines
= lineno
- 1;
592 * Pick up the line numbers of all changes from one change file.
593 * (This puts the numbers in a vector, which is not strictly necessary,
594 * since the vector is processed in one sequential pass.
595 * The vector could be optimized out of existence)
597 static const struct got_error
*
598 readin(size_t *n
, char *name
, struct diff
**dd
, struct diff3_state
*d3s
)
600 const struct got_error
*err
= NULL
;
608 f
= fopen(name
, "re");
610 return got_error_from_errno2("fopen", name
);
611 err
= getchange(&p
, f
, d3s
);
614 for (i
= 0; p
; i
++) {
615 if (i
>= d3s
->szchanges
- 1) {
637 (*dd
)[i
].old
.from
= a
;
639 (*dd
)[i
].new.from
= c
;
642 err
= getchange(&p
, f
, d3s
);
648 (*dd
)[i
].old
.from
= (*dd
)[i
- 1].old
.to
;
649 (*dd
)[i
].new.from
= (*dd
)[i
- 1].new.to
;
652 if (fclose(f
) == EOF
&& err
== NULL
)
653 err
= got_error_from_errno("fclose");
665 while (isdigit((unsigned char)(**lc
)))
666 nn
= nn
*10 + *(*lc
)++ - '0';
671 static const struct got_error
*
672 getchange(char **line
, FILE *b
, struct diff3_state
*d3s
)
674 const struct got_error
*err
= NULL
;
678 if (*line
&& isdigit((unsigned char)(*line
)[0]))
680 err
= get_line(line
, b
, NULL
, d3s
);
688 static const struct got_error
*
689 get_line(char **ret
, FILE *b
, size_t *n
, struct diff3_state
*d3s
)
691 const struct got_error
*err
= NULL
;
701 len
= getline(&cp
, &size
, b
);
704 err
= got_error_from_errno("getline");
708 if (cp
[len
- 1] != '\n') {
710 if (len
+ 1 > size
) {
711 new = realloc(cp
, len
+ 1);
713 err
= got_error_from_errno("realloc");
723 *ret
= d3s
->buf
= cp
;
732 static const struct got_error
*
733 merge(size_t m1
, size_t m2
, struct diff3_state
*d3s
)
735 const struct got_error
*err
= NULL
;
736 struct diff
*d1
, *d2
;
743 t1
= (d1
< d3s
->d13
+ m1
);
744 t2
= (d2
< d3s
->d23
+ m2
);
748 /* first file is different from others */
749 if (!t2
|| (t1
&& d1
->new.to
< d2
->new.from
)) {
750 /* stuff peculiar to 1st file */
755 /* second file is different from others */
756 if (!t1
|| (t2
&& d2
->new.to
< d1
->new.from
)) {
762 * Merge overlapping changes in first file
763 * this happens after extension (see below).
765 if (d1
+ 1 < d3s
->d13
+ m1
&& d1
->new.to
>= d1
[1].new.from
) {
766 d1
[1].old
.from
= d1
->old
.from
;
767 d1
[1].new.from
= d1
->new.from
;
772 /* merge overlapping changes in second */
773 if (d2
+ 1 < d3s
->d23
+ m2
&& d2
->new.to
>= d2
[1].new.from
) {
774 d2
[1].old
.from
= d2
->old
.from
;
775 d2
[1].new.from
= d2
->new.from
;
779 /* stuff peculiar to third file or different in all */
780 if (d1
->new.from
== d2
->new.from
&& d1
->new.to
== d2
->new.to
) {
781 err
= duplicate(&dpl
, j
, &d1
->old
, &d2
->old
, d3s
);
786 * dpl = 0 means all files differ
787 * dpl = 1 means files 1 and 2 identical
789 err
= edit(d1
, dpl
, &j
, d3s
);
798 * Overlapping changes from file 1 and 2; extend changes
799 * appropriately to make them coincide.
801 if (d1
->new.from
< d2
->new.from
) {
802 d2
->old
.from
-= d2
->new.from
- d1
->new.from
;
803 d2
->new.from
= d1
->new.from
;
804 } else if (d2
->new.from
< d1
->new.from
) {
805 d1
->old
.from
-= d1
->new.from
- d2
->new.from
;
806 d1
->new.from
= d2
->new.from
;
808 if (d1
->new.to
> d2
->new.to
) {
809 d2
->old
.to
+= d1
->new.to
- d2
->new.to
;
810 d2
->new.to
= d1
->new.to
;
811 } else if (d2
->new.to
> d1
->new.to
) {
812 d1
->old
.to
+= d2
->new.to
- d1
->new.to
;
813 d1
->new.to
= d2
->new.to
;
817 return (edscript(j
, d3s
));
821 * print the range of line numbers, rold.from thru rold.to, as n1,n2 or n1
823 static const struct got_error
*
824 prange(struct line_range
*rold
, struct diff3_state
*d3s
)
826 const struct got_error
*err
= NULL
;
828 if (rold
->to
<= rold
->from
) {
829 err
= diff_output(d3s
->diffbuf
, "%da\n", rold
->from
- 1);
833 err
= diff_output(d3s
->diffbuf
, "%d", rold
->from
);
836 if (rold
->to
> rold
->from
+ 1) {
837 err
= diff_output(d3s
->diffbuf
, ",%d", rold
->to
- 1);
841 err
= diff_output(d3s
->diffbuf
, "c\n");
850 * Skip to just before line number from in file "i".
851 * Return the number of bytes skipped in *nskipped.
853 static const struct got_error
*
854 skip(size_t *nskipped
, int i
, int from
, struct diff3_state
*d3s
)
856 const struct got_error
*err
= NULL
;
861 for (n
= 0; d3s
->cline
[i
] < from
- 1; n
+= len
) {
862 err
= get_line(&line
, d3s
->fp
[i
], &len
, d3s
);
872 * Set *dpl to 1 or 0 according as the old range (in file 1) contains exactly
873 * the same data as the new range (in file 2).
875 * If this change could overlap, remember start/end offsets in file 2 so we
876 * can write out the original lines of text if a merge conflict occurs.
878 static const struct got_error
*
879 duplicate(int *dpl
, int j
, struct line_range
*r1
, struct line_range
*r2
,
880 struct diff3_state
*d3s
)
882 const struct got_error
*err
= NULL
;
891 if (r1
->to
- r1
->from
!= r2
->to
- r2
->from
)
894 err
= skip(&nskipped
, 0, r1
->from
, d3s
);
897 err
= skip(&nskipped
, 1, r2
->from
, d3s
);
901 off
= ftello(d3s
->fp
[1]);
903 return got_error_from_errno("ftello");
904 d3s
->de
[j
+ 1].oldo
.from
= off
; /* original lines start here */
907 for (nline
= 0; nline
< r1
->to
- r1
->from
; nline
++) {
909 c
= getc(d3s
->fp
[0]);
910 d
= getc(d3s
->fp
[1]);
911 if (c
== EOF
&& d
== EOF
)
914 return got_ferror(d3s
->fp
[0], GOT_ERR_EOF
);
916 return got_ferror(d3s
->fp
[1], GOT_ERR_EOF
);
919 long orig_line_len
= nchar
;
921 d
= getc(d3s
->fp
[1]);
926 if (orig_line_len
> nchar
&&
927 fseek(d3s
->fp
[1], -(orig_line_len
- nchar
),
929 return got_ferror(d3s
->fp
[1],
931 /* original lines end here */
932 d3s
->de
[j
+ 1].oldo
.to
= off
+ orig_line_len
;
933 err
= repos(nchar
, d3s
);
941 /* original lines end here */
942 d3s
->de
[j
+ 1].oldo
.to
= off
+ nchar
;
944 err
= repos(nchar
, d3s
);
951 static const struct got_error
*
952 repos(int nchar
, struct diff3_state
*d3s
)
956 for (i
= 0; i
< 2; i
++) {
957 if (fseek(d3s
->fp
[i
], (long)-nchar
, SEEK_CUR
) == -1)
958 return got_ferror(d3s
->fp
[i
], GOT_ERR_IO
);
965 * collect an editing script for later regurgitation
967 static const struct got_error
*
968 edit(struct diff
*diff
, int fdup
, int *j
, struct diff3_state
*d3s
)
970 const struct got_error
*err
= NULL
;
973 if (((fdup
+ 1) & 3) == 0)
976 d3s
->overlap
[*j
] = !fdup
;
979 d3s
->de
[*j
].old
.from
= diff
->old
.from
;
980 d3s
->de
[*j
].old
.to
= diff
->old
.to
;
982 err
= skip(&nskipped
, 2, diff
->new.from
, d3s
);
985 d3s
->de
[*j
].newo
.from
= d3s
->de
[*j
- 1].newo
.to
+ nskipped
;
987 err
= skip(&nskipped
, 2, diff
->new.to
, d3s
);
990 d3s
->de
[*j
].newo
.to
= d3s
->de
[*j
].newo
.from
+ nskipped
;
995 static const struct got_error
*
996 edscript(int n
, struct diff3_state
*d3s
)
998 const struct got_error
*err
= NULL
;
1001 size_t linesize
= 0;
1002 ssize_t linelen
= 0, k
;
1004 for (; n
> 0; n
--) {
1005 if (!d3s
->overlap
[n
]) {
1006 err
= prange(&d3s
->de
[n
].old
, d3s
);
1009 } else if (d3s
->de
[n
].oldo
.from
< d3s
->de
[n
].oldo
.to
) {
1010 /* Output a block of 3-way diff base file content. */
1011 err
= diff_output(d3s
->diffbuf
, "%da\n:%s\n",
1012 d3s
->de
[n
].old
.to
- 1, d3s
->f2mark
);
1015 if (fseeko(d3s
->fp
[1], d3s
->de
[n
].oldo
.from
, SEEK_SET
)
1017 return got_error_from_errno("fseeko");
1018 len
= (d3s
->de
[n
].oldo
.to
- d3s
->de
[n
].oldo
.from
);
1019 for (k
= 0; k
< (ssize_t
)len
; k
+= linelen
) {
1020 linelen
= getline(&line
, &linesize
, d3s
->fp
[1]);
1021 if (linelen
== -1) {
1022 if (feof(d3s
->fp
[1]))
1024 err
= got_ferror(d3s
->fp
[1],
1028 err
= diff_output(d3s
->diffbuf
, ":%s", line
);
1032 err
= diff_output(d3s
->diffbuf
, "%s%s\n",
1033 linelen
> 0 && line
[linelen
] == '\n' ? ":" : "",
1034 GOT_DIFF_CONFLICT_MARKER_SEP
);
1038 err
= diff_output(d3s
->diffbuf
, "%da\n:%s\n",
1039 d3s
->de
[n
].old
.to
-1, GOT_DIFF_CONFLICT_MARKER_SEP
);
1043 if (fseeko(d3s
->fp
[2], d3s
->de
[n
].newo
.from
, SEEK_SET
)
1045 err
= got_error_from_errno("fseek");
1048 len
= (d3s
->de
[n
].newo
.to
- d3s
->de
[n
].newo
.from
);
1049 for (k
= 0; k
< (ssize_t
)len
; k
+= linelen
) {
1050 linelen
= getline(&line
, &linesize
, d3s
->fp
[2]);
1051 if (linelen
== -1) {
1052 if (feof(d3s
->fp
[2]))
1054 err
= got_ferror(d3s
->fp
[2], GOT_ERR_IO
);
1057 err
= diff_output(d3s
->diffbuf
, ":%s", line
);
1062 if (!d3s
->overlap
[n
]) {
1063 err
= diff_output(d3s
->diffbuf
, ".\n");
1067 err
= diff_output(d3s
->diffbuf
, "%s%s\n.\n",
1068 linelen
> 0 && line
[linelen
] == '\n' ? ":" : "",
1072 err
= diff_output(d3s
->diffbuf
, "%da\n:%s\n.\n",
1073 d3s
->de
[n
].old
.from
- 1, d3s
->f1mark
);
1083 static const struct got_error
*
1084 increase(struct diff3_state
*d3s
)
1090 /* are the memset(3) calls needed? */
1091 newsz
= d3s
->szchanges
== 0 ? 64 : 2 * d3s
->szchanges
;
1092 incr
= newsz
- d3s
->szchanges
;
1094 d
= reallocarray(d3s
->d13
, newsz
, sizeof(*d3s
->d13
));
1096 return got_error_from_errno("reallocarray");
1098 memset(d3s
->d13
+ d3s
->szchanges
, 0, incr
* sizeof(*d3s
->d13
));
1100 d
= reallocarray(d3s
->d23
, newsz
, sizeof(*d3s
->d23
));
1102 return got_error_from_errno("reallocarray");
1104 memset(d3s
->d23
+ d3s
->szchanges
, 0, incr
* sizeof(*d3s
->d23
));
1106 d
= reallocarray(d3s
->de
, newsz
, sizeof(*d3s
->de
));
1108 return got_error_from_errno("reallocarray");
1110 memset(d3s
->de
+ d3s
->szchanges
, 0, incr
* sizeof(*d3s
->de
));
1112 s
= reallocarray(d3s
->overlap
, newsz
, sizeof(*d3s
->overlap
));
1114 return got_error_from_errno("reallocarray");
1116 memset(d3s
->overlap
+ d3s
->szchanges
, 0, incr
* sizeof(*d3s
->overlap
));
1117 d3s
->szchanges
= newsz
;