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
];
158 int no_eofnl
; /* set if the merged file has no eof newline */
164 static const struct got_error
*duplicate(int *, int, struct line_range
*,
165 struct line_range
*, struct diff3_state
*);
166 static const struct got_error
*edit(struct diff
*, int, int *,
167 struct diff3_state
*);
168 static const struct got_error
*getchange(char **, FILE *, struct diff3_state
*);
169 static const struct got_error
*get_line(char **, FILE *, size_t *,
170 struct diff3_state
*);
171 static int number(char **);
172 static const struct got_error
*readin(size_t *, char *, struct diff
**,
173 struct diff3_state
*);
174 static int ed_patch_lines(struct rcs_lines
*, struct rcs_lines
*);
175 static const struct got_error
*skip(size_t *, int, int, struct diff3_state
*);
176 static const struct got_error
*edscript(int, struct diff3_state
*);
177 static const struct got_error
*merge(size_t, size_t, struct diff3_state
*);
178 static const struct got_error
*prange(struct line_range
*,
179 struct diff3_state
*);
180 static const struct got_error
*repos(int, struct diff3_state
*);
181 static const struct got_error
*increase(struct diff3_state
*);
182 static const struct got_error
*diff3_internal(char *, char *, char *,
183 char *, char *, const char *, const char *, struct diff3_state
*,
184 const char *, const char *, const char *);
186 static const struct got_error
*
187 diff_output(BUF
*diffbuf
, const char *fmt
, ...)
189 const struct got_error
*err
= NULL
;
196 i
= vasprintf(&str
, fmt
, vap
);
199 return got_error_from_errno("vasprintf");
200 err
= buf_append(&newsize
, diffbuf
, str
, strlen(str
));
205 static const struct got_error
*
206 diffreg(BUF
**d
, const char *path1
, const char *path2
,
207 enum got_diff_algorithm diff_algo
)
209 const struct got_error
*err
= NULL
;
210 FILE *f1
= NULL
, *f2
= NULL
, *outfile
= NULL
;
211 char *outpath
= NULL
;
212 struct got_diffreg_result
*diffreg_result
= NULL
;
216 f1
= fopen(path1
, "re");
218 err
= got_error_from_errno2("fopen", path1
);
221 f2
= fopen(path2
, "re");
223 err
= got_error_from_errno2("fopen", path2
);
227 err
= got_opentemp_named(&outpath
, &outfile
,
228 GOT_TMPDIR_STR
"/got-diffreg", "");
232 err
= got_diffreg(&diffreg_result
, f1
, f2
, diff_algo
, 0, 0);
236 if (diffreg_result
) {
237 struct diff_result
*diff_result
= diffreg_result
->result
;
238 int atomizer_flags
= (diff_result
->left
->atomizer_flags
|
239 diff_result
->right
->atomizer_flags
);
240 if ((atomizer_flags
& DIFF_ATOMIZER_FOUND_BINARY_DATA
)) {
241 err
= got_error(GOT_ERR_FILE_BINARY
);
246 err
= got_diffreg_output(NULL
, NULL
, diffreg_result
, 1, 1, "", "",
247 GOT_DIFF_OUTPUT_PLAIN
, 0, outfile
);
251 if (fflush(outfile
) != 0) {
252 err
= got_error_from_errno2("fflush", outpath
);
255 if (fseek(outfile
, 0L, SEEK_SET
) == -1) {
256 err
= got_ferror(outfile
, GOT_ERR_IO
);
260 err
= buf_load(d
, outfile
);
263 if (unlink(outpath
) == -1 && err
== NULL
)
264 err
= got_error_from_errno2("unlink", outpath
);
267 if (outfile
&& fclose(outfile
) == EOF
&& err
== NULL
)
268 err
= got_error_from_errno("fclose");
269 if (f1
&& fclose(f1
) == EOF
&& err
== NULL
)
270 err
= got_error_from_errno("fclose");
271 if (f2
&& fclose(f2
) == EOF
&& err
== NULL
)
272 err
= got_error_from_errno("fclose");
279 const struct got_error
*
280 got_merge_diff3(int *overlapcnt
, int outfd
, FILE *f1
, FILE *f2
,
281 FILE *f3
, const char *label1
, const char *label2
, const char *label3
,
282 enum got_diff_algorithm diff_algo
)
284 const struct got_error
*err
= NULL
;
285 char *dp13
, *dp23
, *path1
, *path2
, *path3
;
286 BUF
*b1
, *b2
, *b3
, *d1
, *d2
, *diffb
;
287 u_char
*data
, *patch
;
288 size_t dlen
, plen
, i
;
289 struct diff3_state
*d3s
;
293 d3s
= calloc(1, sizeof(*d3s
));
295 return got_error_from_errno("calloc");
297 b1
= b2
= b3
= d1
= d2
= diffb
= NULL
;
298 dp13
= dp23
= path1
= path2
= path3
= NULL
;
301 err
= buf_load(&b1
, f1
);
304 err
= buf_load(&b2
, f2
);
307 err
= buf_load(&b3
, f3
);
311 err
= buf_alloc(&diffb
, 128);
315 if (asprintf(&path1
, GOT_TMPDIR_STR
"/got-diff1.XXXXXXXXXX") == -1) {
316 err
= got_error_from_errno("asprintf");
319 if (asprintf(&path2
, GOT_TMPDIR_STR
"/got-diff2.XXXXXXXXXX") == -1) {
320 err
= got_error_from_errno("asprintf");
323 if (asprintf(&path3
, GOT_TMPDIR_STR
"/got-diff3.XXXXXXXXXX") == -1) {
324 err
= got_error_from_errno("asprintf");
328 err
= buf_write_stmp(b1
, path1
);
331 err
= buf_write_stmp(b2
, path2
);
334 err
= buf_write_stmp(b3
, path3
);
341 err
= diffreg(&d1
, path1
, path3
, diff_algo
);
348 err
= diffreg(&d2
, path2
, path3
, diff_algo
);
355 if (asprintf(&dp13
, GOT_TMPDIR_STR
"/got-d13.XXXXXXXXXX") == -1) {
356 err
= got_error_from_errno("asprintf");
359 err
= buf_write_stmp(d1
, dp13
);
366 if (asprintf(&dp23
, GOT_TMPDIR_STR
"/got-d23.XXXXXXXXXX") == -1) {
367 err
= got_error_from_errno("asprintf");
370 err
= buf_write_stmp(d2
, dp23
);
377 d3s
->diffbuf
= diffb
;
378 err
= diff3_internal(dp13
, dp23
, path1
, path2
, path3
,
379 label1
, label3
, d3s
, label1
, label2
, label3
);
386 plen
= buf_len(diffb
);
387 patch
= buf_release(diffb
);
389 data
= buf_release(b1
);
391 diffb
= rcs_patchfile(data
, dlen
, patch
, plen
, ed_patch_lines
);
398 if (unlink(path1
) == -1 && err
== NULL
)
399 err
= got_error_from_errno2("unlink", path1
);
400 if (unlink(path2
) == -1 && err
== NULL
)
401 err
= got_error_from_errno2("unlink", path2
);
402 if (unlink(path3
) == -1 && err
== NULL
)
403 err
= got_error_from_errno2("unlink", path3
);
404 if (unlink(dp13
) == -1 && err
== NULL
)
405 err
= got_error_from_errno2("unlink", dp13
);
406 if (unlink(dp23
) == -1 && err
== NULL
)
407 err
= got_error_from_errno2("unlink", dp23
);
417 for (i
= 0; i
< nitems(d3s
->fp
); i
++) {
418 if (d3s
->fp
[i
] && fclose(d3s
->fp
[i
]) == EOF
&& err
== NULL
)
419 err
= got_error_from_errno("fclose");
421 if (err
== NULL
&& diffb
) {
422 dlen
= buf_len(diffb
);
423 if (d3s
->no_eofnl
&& dlen
> 0 &&
424 buf_getc(diffb
, dlen
- 1) == '\n')
426 if (buf_write_fd(diffb
, outfd
) < 0)
427 err
= got_error_from_errno("buf_write_fd");
428 *overlapcnt
= d3s
->overlapcnt
;
435 static const struct got_error
*
436 diff3_internal(char *dp13
, char *dp23
, char *path1
, char *path2
, char *path3
,
437 const char *fmark
, const char *rmark
, struct diff3_state
*d3s
,
438 const char *label1
, const char *label2
, const char *label3
)
440 const struct got_error
*err
= NULL
;
444 i
= snprintf(d3s
->f1mark
, sizeof(d3s
->f1mark
),
445 "%s%s%s", GOT_DIFF_CONFLICT_MARKER_BEGIN
,
446 label1
? " " : "", label1
? label1
: "");
447 if (i
< 0 || i
>= (int)sizeof(d3s
->f1mark
))
448 return got_error(GOT_ERR_NO_SPACE
);
450 i
= snprintf(d3s
->f2mark
, sizeof(d3s
->f2mark
),
451 "%s%s%s", GOT_DIFF_CONFLICT_MARKER_ORIG
,
452 label2
? " " : "", label2
? label2
: "");
453 if (i
< 0 || i
>= (int)sizeof(d3s
->f2mark
))
454 return got_error(GOT_ERR_NO_SPACE
);
456 i
= snprintf(d3s
->f3mark
, sizeof(d3s
->f3mark
),
457 "%s%s%s", GOT_DIFF_CONFLICT_MARKER_END
,
458 label3
? " " : "", label3
? label3
: "");
459 if (i
< 0 || i
>= (int)sizeof(d3s
->f3mark
))
460 return got_error(GOT_ERR_NO_SPACE
);
466 err
= readin(&m
, dp13
, &d3s
->d13
, d3s
);
469 err
= readin(&n
, dp23
, &d3s
->d23
, d3s
);
473 if ((d3s
->fp
[0] = fopen(path1
, "re")) == NULL
)
474 return got_error_from_errno2("fopen", path1
);
475 if ((d3s
->fp
[1] = fopen(path2
, "re")) == NULL
)
476 return got_error_from_errno2("fopen", path2
);
477 if ((d3s
->fp
[2] = fopen(path3
, "re")) == NULL
)
478 return got_error_from_errno2("fopen", path3
);
480 return merge(m
, n
, d3s
);
484 ed_patch_lines(struct rcs_lines
*dlines
, struct rcs_lines
*plines
)
487 struct rcs_line
*sort
, *lp
, *dlp
, *ndlp
, *insert_after
;
488 int start
, end
, i
, lineno
;
491 dlp
= TAILQ_FIRST(&(dlines
->l_lines
));
492 lp
= TAILQ_FIRST(&(plines
->l_lines
));
495 for (lp
= TAILQ_NEXT(lp
, l_list
); lp
!= NULL
;
496 lp
= TAILQ_NEXT(lp
, l_list
)) {
497 /* Skip blank lines */
501 /* NUL-terminate line buffer for strtol() safety. */
502 tmp
= lp
->l_line
[lp
->l_len
- 1];
503 lp
->l_line
[lp
->l_len
- 1] = '\0';
505 /* len - 1 is NUL terminator so we use len - 2 for 'op' */
506 op
= lp
->l_line
[lp
->l_len
- 2];
507 start
= (int)strtol(lp
->l_line
, &ep
, 10);
509 /* Restore the last byte of the buffer */
510 lp
->l_line
[lp
->l_len
- 1] = tmp
;
513 if (start
> dlines
->l_nblines
||
514 start
< 0 || *ep
!= 'a')
516 } else if (op
== 'c') {
517 if (start
> dlines
->l_nblines
||
518 start
< 0 || (*ep
!= ',' && *ep
!= 'c'))
523 end
= (int)strtol(ep
, &ep
, 10);
524 if (end
< 0 || *ep
!= 'c')
535 if (dlp
->l_lineno
== start
)
537 if (dlp
->l_lineno
> start
) {
538 dlp
= TAILQ_PREV(dlp
, tqh
, l_list
);
539 } else if (dlp
->l_lineno
< start
) {
540 ndlp
= TAILQ_NEXT(dlp
, l_list
);
541 if (ndlp
->l_lineno
> start
)
552 insert_after
= TAILQ_PREV(dlp
, tqh
, l_list
);
553 for (i
= 0; i
<= (end
- start
); i
++) {
554 ndlp
= TAILQ_NEXT(dlp
, l_list
);
555 TAILQ_REMOVE(&(dlines
->l_lines
), dlp
, l_list
);
561 if (op
== 'a' || op
== 'c') {
564 lp
= TAILQ_NEXT(lp
, l_list
);
568 if (lp
->l_len
== 2 &&
569 lp
->l_line
[0] == '.' &&
570 lp
->l_line
[1] == '\n')
573 if (lp
->l_line
[0] == ':') {
577 TAILQ_REMOVE(&(plines
->l_lines
), lp
, l_list
);
578 TAILQ_INSERT_AFTER(&(dlines
->l_lines
), dlp
,
582 lp
->l_lineno
= start
;
588 * always resort lines as the markers might be put at the
589 * same line as we first started editing.
592 TAILQ_FOREACH(sort
, &(dlines
->l_lines
), l_list
)
593 sort
->l_lineno
= lineno
++;
594 dlines
->l_nblines
= lineno
- 1;
601 * Pick up the line numbers of all changes from one change file.
602 * (This puts the numbers in a vector, which is not strictly necessary,
603 * since the vector is processed in one sequential pass.
604 * The vector could be optimized out of existence)
606 static const struct got_error
*
607 readin(size_t *n
, char *name
, struct diff
**dd
, struct diff3_state
*d3s
)
609 const struct got_error
*err
= NULL
;
617 f
= fopen(name
, "re");
619 return got_error_from_errno2("fopen", name
);
620 err
= getchange(&p
, f
, d3s
);
623 for (i
= 0; p
; i
++) {
624 if (i
>= d3s
->szchanges
- 1) {
646 (*dd
)[i
].old
.from
= a
;
648 (*dd
)[i
].new.from
= c
;
651 err
= getchange(&p
, f
, d3s
);
657 (*dd
)[i
].old
.from
= (*dd
)[i
- 1].old
.to
;
658 (*dd
)[i
].new.from
= (*dd
)[i
- 1].new.to
;
661 if (fclose(f
) == EOF
&& err
== NULL
)
662 err
= got_error_from_errno("fclose");
674 while (isdigit((unsigned char)(**lc
)))
675 nn
= nn
*10 + *(*lc
)++ - '0';
680 static const struct got_error
*
681 getchange(char **line
, FILE *b
, struct diff3_state
*d3s
)
683 const struct got_error
*err
= NULL
;
687 if (*line
&& isdigit((unsigned char)(*line
)[0]))
689 err
= get_line(line
, b
, NULL
, d3s
);
697 static const struct got_error
*
698 get_line(char **ret
, FILE *b
, size_t *n
, struct diff3_state
*d3s
)
700 const struct got_error
*err
= NULL
;
710 len
= getline(&cp
, &size
, b
);
713 err
= got_error_from_errno("getline");
717 if (cp
[len
- 1] != '\n') {
719 if (len
+ 1 > size
) {
720 new = realloc(cp
, len
+ 1);
722 err
= got_error_from_errno("realloc");
732 *ret
= d3s
->buf
= cp
;
741 static const struct got_error
*
742 merge(size_t m1
, size_t m2
, struct diff3_state
*d3s
)
744 const struct got_error
*err
= NULL
;
745 struct diff
*d1
, *d2
;
752 t1
= (d1
< d3s
->d13
+ m1
);
753 t2
= (d2
< d3s
->d23
+ m2
);
757 /* first file is different from others */
758 if (!t2
|| (t1
&& d1
->new.to
< d2
->new.from
)) {
759 /* stuff peculiar to 1st file */
764 /* second file is different from others */
765 if (!t1
|| (t2
&& d2
->new.to
< d1
->new.from
)) {
771 * Merge overlapping changes in first file
772 * this happens after extension (see below).
774 if (d1
+ 1 < d3s
->d13
+ m1
&& d1
->new.to
>= d1
[1].new.from
) {
775 d1
[1].old
.from
= d1
->old
.from
;
776 d1
[1].new.from
= d1
->new.from
;
781 /* merge overlapping changes in second */
782 if (d2
+ 1 < d3s
->d23
+ m2
&& d2
->new.to
>= d2
[1].new.from
) {
783 d2
[1].old
.from
= d2
->old
.from
;
784 d2
[1].new.from
= d2
->new.from
;
788 /* stuff peculiar to third file or different in all */
789 if (d1
->new.from
== d2
->new.from
&& d1
->new.to
== d2
->new.to
) {
790 err
= duplicate(&dpl
, j
, &d1
->old
, &d2
->old
, d3s
);
795 * dpl = 0 means all files differ
796 * dpl = 1 means files 1 and 2 identical
798 err
= edit(d1
, dpl
, &j
, d3s
);
807 * Overlapping changes from file 1 and 2; extend changes
808 * appropriately to make them coincide.
810 if (d1
->new.from
< d2
->new.from
) {
811 d2
->old
.from
-= d2
->new.from
- d1
->new.from
;
812 d2
->new.from
= d1
->new.from
;
813 } else if (d2
->new.from
< d1
->new.from
) {
814 d1
->old
.from
-= d1
->new.from
- d2
->new.from
;
815 d1
->new.from
= d2
->new.from
;
817 if (d1
->new.to
> d2
->new.to
) {
818 d2
->old
.to
+= d1
->new.to
- d2
->new.to
;
819 d2
->new.to
= d1
->new.to
;
820 } else if (d2
->new.to
> d1
->new.to
) {
821 d1
->old
.to
+= d2
->new.to
- d1
->new.to
;
822 d1
->new.to
= d2
->new.to
;
826 return (edscript(j
, d3s
));
830 * print the range of line numbers, rold.from thru rold.to, as n1,n2 or n1
832 static const struct got_error
*
833 prange(struct line_range
*rold
, struct diff3_state
*d3s
)
835 const struct got_error
*err
= NULL
;
837 if (rold
->to
<= rold
->from
) {
838 err
= diff_output(d3s
->diffbuf
, "%da\n", rold
->from
- 1);
842 err
= diff_output(d3s
->diffbuf
, "%d", rold
->from
);
845 if (rold
->to
> rold
->from
+ 1) {
846 err
= diff_output(d3s
->diffbuf
, ",%d", rold
->to
- 1);
850 err
= diff_output(d3s
->diffbuf
, "c\n");
859 * Skip to just before line number from in file "i".
860 * Return the number of bytes skipped in *nskipped.
862 static const struct got_error
*
863 skip(size_t *nskipped
, int i
, int from
, struct diff3_state
*d3s
)
865 const struct got_error
*err
= NULL
;
870 for (n
= 0; d3s
->cline
[i
] < from
- 1; n
+= len
) {
871 err
= get_line(&line
, d3s
->fp
[i
], &len
, d3s
);
881 * Set *dpl to 1 or 0 according as the old range (in file 1) contains exactly
882 * the same data as the new range (in file 2).
884 * If this change could overlap, remember start/end offsets in file 2 so we
885 * can write out the original lines of text if a merge conflict occurs.
887 static const struct got_error
*
888 duplicate(int *dpl
, int j
, struct line_range
*r1
, struct line_range
*r2
,
889 struct diff3_state
*d3s
)
891 const struct got_error
*err
= NULL
;
900 if (r1
->to
- r1
->from
!= r2
->to
- r2
->from
)
903 err
= skip(&nskipped
, 0, r1
->from
, d3s
);
906 err
= skip(&nskipped
, 1, r2
->from
, d3s
);
910 off
= ftello(d3s
->fp
[1]);
912 return got_error_from_errno("ftello");
913 d3s
->de
[j
+ 1].oldo
.from
= off
; /* original lines start here */
916 for (nline
= 0; nline
< r1
->to
- r1
->from
; nline
++) {
918 c
= getc(d3s
->fp
[0]);
919 d
= getc(d3s
->fp
[1]);
920 if (c
== EOF
&& d
== EOF
)
923 return got_ferror(d3s
->fp
[0], GOT_ERR_EOF
);
925 return got_ferror(d3s
->fp
[1], GOT_ERR_EOF
);
928 long orig_line_len
= nchar
;
930 d
= getc(d3s
->fp
[1]);
935 if (orig_line_len
> nchar
&&
936 fseek(d3s
->fp
[1], -(orig_line_len
- nchar
),
938 return got_ferror(d3s
->fp
[1],
940 /* original lines end here */
941 d3s
->de
[j
+ 1].oldo
.to
= off
+ orig_line_len
;
942 err
= repos(nchar
, d3s
);
950 /* original lines end here */
951 d3s
->de
[j
+ 1].oldo
.to
= off
+ nchar
;
953 err
= repos(nchar
, d3s
);
960 static const struct got_error
*
961 repos(int nchar
, struct diff3_state
*d3s
)
965 for (i
= 0; i
< 2; i
++) {
966 if (fseek(d3s
->fp
[i
], (long)-nchar
, SEEK_CUR
) == -1)
967 return got_ferror(d3s
->fp
[i
], GOT_ERR_IO
);
974 * collect an editing script for later regurgitation
976 static const struct got_error
*
977 edit(struct diff
*diff
, int fdup
, int *j
, struct diff3_state
*d3s
)
979 const struct got_error
*err
= NULL
;
982 if (((fdup
+ 1) & 3) == 0)
985 d3s
->overlap
[*j
] = !fdup
;
988 d3s
->de
[*j
].old
.from
= diff
->old
.from
;
989 d3s
->de
[*j
].old
.to
= diff
->old
.to
;
991 err
= skip(&nskipped
, 2, diff
->new.from
, d3s
);
994 d3s
->de
[*j
].newo
.from
= d3s
->de
[*j
- 1].newo
.to
+ nskipped
;
996 err
= skip(&nskipped
, 2, diff
->new.to
, d3s
);
999 d3s
->de
[*j
].newo
.to
= d3s
->de
[*j
].newo
.from
+ nskipped
;
1004 static const struct got_error
*
1005 edscript(int n
, struct diff3_state
*d3s
)
1007 const struct got_error
*err
= NULL
;
1010 size_t linesize
= 0;
1011 ssize_t linelen
= 0, k
;
1013 for (; n
> 0; n
--) {
1014 if (!d3s
->overlap
[n
]) {
1015 err
= prange(&d3s
->de
[n
].old
, d3s
);
1018 } else if (d3s
->de
[n
].oldo
.from
< d3s
->de
[n
].oldo
.to
) {
1019 /* Output a block of 3-way diff base file content. */
1020 err
= diff_output(d3s
->diffbuf
, "%da\n:%s\n",
1021 d3s
->de
[n
].old
.to
- 1, d3s
->f2mark
);
1024 if (fseeko(d3s
->fp
[1], d3s
->de
[n
].oldo
.from
, SEEK_SET
)
1026 return got_error_from_errno("fseeko");
1027 len
= (d3s
->de
[n
].oldo
.to
- d3s
->de
[n
].oldo
.from
);
1028 for (k
= 0; k
< (ssize_t
)len
; k
+= linelen
) {
1029 linelen
= getline(&line
, &linesize
, d3s
->fp
[1]);
1030 if (linelen
== -1) {
1031 if (feof(d3s
->fp
[1]))
1033 err
= got_ferror(d3s
->fp
[1],
1037 err
= diff_output(d3s
->diffbuf
, ":%s", line
);
1041 err
= diff_output(d3s
->diffbuf
, "%s%s\n",
1042 linelen
> 0 && line
[linelen
] == '\n' ? ":" : "",
1043 GOT_DIFF_CONFLICT_MARKER_SEP
);
1047 err
= diff_output(d3s
->diffbuf
, "%da\n:%s\n",
1048 d3s
->de
[n
].old
.to
-1, GOT_DIFF_CONFLICT_MARKER_SEP
);
1052 if (fseeko(d3s
->fp
[2], d3s
->de
[n
].newo
.from
, SEEK_SET
)
1054 err
= got_error_from_errno("fseek");
1057 len
= (d3s
->de
[n
].newo
.to
- d3s
->de
[n
].newo
.from
);
1058 for (k
= 0; k
< (ssize_t
)len
; k
+= linelen
) {
1059 linelen
= getline(&line
, &linesize
, d3s
->fp
[2]);
1060 if (linelen
== -1) {
1061 if (feof(d3s
->fp
[2]))
1063 err
= got_ferror(d3s
->fp
[2], GOT_ERR_IO
);
1066 err
= diff_output(d3s
->diffbuf
, ":%s", line
);
1071 if (!d3s
->overlap
[n
]) {
1074 len
= buf_len(d3s
->diffbuf
);
1076 if (buf_getc(d3s
->diffbuf
, len
- 1) != '\n') {
1077 err
= buf_putc(d3s
->diffbuf
, '\n');
1083 err
= diff_output(d3s
->diffbuf
, ".\n");
1087 err
= diff_output(d3s
->diffbuf
, "%s%s\n.\n",
1088 linelen
> 0 && line
[linelen
] == '\n' ? ":" : "",
1092 err
= diff_output(d3s
->diffbuf
, "%da\n:%s\n.\n",
1093 d3s
->de
[n
].old
.from
- 1, d3s
->f1mark
);
1103 static const struct got_error
*
1104 increase(struct diff3_state
*d3s
)
1110 /* are the memset(3) calls needed? */
1111 newsz
= d3s
->szchanges
== 0 ? 64 : 2 * d3s
->szchanges
;
1112 incr
= newsz
- d3s
->szchanges
;
1114 d
= reallocarray(d3s
->d13
, newsz
, sizeof(*d3s
->d13
));
1116 return got_error_from_errno("reallocarray");
1118 memset(d3s
->d13
+ d3s
->szchanges
, 0, incr
* sizeof(*d3s
->d13
));
1120 d
= reallocarray(d3s
->d23
, newsz
, sizeof(*d3s
->d23
));
1122 return got_error_from_errno("reallocarray");
1124 memset(d3s
->d23
+ d3s
->szchanges
, 0, incr
* sizeof(*d3s
->d23
));
1126 d
= reallocarray(d3s
->de
, newsz
, sizeof(*d3s
->de
));
1128 return got_error_from_errno("reallocarray");
1130 memset(d3s
->de
+ d3s
->szchanges
, 0, incr
* sizeof(*d3s
->de
));
1132 s
= reallocarray(d3s
->overlap
, newsz
, sizeof(*d3s
->overlap
));
1134 return got_error_from_errno("reallocarray");
1136 memset(d3s
->overlap
+ d3s
->szchanges
, 0, incr
* sizeof(*d3s
->overlap
));
1137 d3s
->szchanges
= newsz
;