commit f10244c07ff073c7f69ecf2044ac34e85f0666a0 from: Stefan Sperling date: Mon Oct 11 18:25:11 2021 UTC fix merging of files which contain a dot on a line by itself Annoying bug which we inherited from OpenRCS which inherited it from OpenBSD's diff3 program. ok tracey millert commit - 2c9e323b3e6b33240740c40bbef58acdae141b56 commit + f10244c07ff073c7f69ecf2044ac34e85f0666a0 blob - 957c2c39351c73dff16d9995d46aa9be345f27ef blob + 4619d898de367bdd4a4c3ff090a223135dbb0935 --- lib/diff3.c +++ lib/diff3.c @@ -550,6 +550,10 @@ ed_patch_lines(struct rcs_lines *dlines, struct rcs_li lp->l_line[1] == '\n') break; + if (lp->l_line[0] == ':') { + lp->l_line++; + lp->l_len--; + } TAILQ_REMOVE(&(plines->l_lines), lp, l_list); TAILQ_INSERT_AFTER(&(dlines->l_lines), dlp, lp, l_list); @@ -975,8 +979,10 @@ static const struct got_error * edscript(int n, struct diff3_state *d3s) { const struct got_error *err = NULL; - size_t k, len; - char block[BUFSIZ+1]; + off_t len; + char *line = NULL; + size_t linesize = 0; + ssize_t linelen, k; for (; n > 0; n--) { if (!d3s->overlap[n]) { @@ -985,79 +991,76 @@ edscript(int n, struct diff3_state *d3s) return err; } else if (d3s->de[n].oldo.from < d3s->de[n].oldo.to) { /* Output a block of 3-way diff base file content. */ - err = diff_output(d3s->diffbuf, "%da\n%s\n", + err = diff_output(d3s->diffbuf, "%da\n:%s\n", d3s->de[n].old.to - 1, d3s->f2mark); if (err) return err; if (fseeko(d3s->fp[1], d3s->de[n].oldo.from, SEEK_SET) == -1) return got_error_from_errno("fseeko"); - k = (size_t)(d3s->de[n].oldo.to - d3s->de[n].oldo.from); - for (; k > 0; k -= len) { - size_t r; - len = k > BUFSIZ ? BUFSIZ : k; - r = fread(block, 1, len, d3s->fp[1]); - if (r == 0) { + len = (d3s->de[n].oldo.to - d3s->de[n].oldo.from); + for (k = 0; k < (ssize_t)len; k += linelen) { + linelen = getline(&line, &linesize, d3s->fp[1]); + if (linelen == -1) { if (feof(d3s->fp[1])) break; - return got_ferror(d3s->fp[1], + err = got_ferror(d3s->fp[1], GOT_ERR_IO); + goto done; } - if (r != len) - len = r; - block[len] = '\0'; - err = diff_output(d3s->diffbuf, "%s", block); + err = diff_output(d3s->diffbuf, ":%s", line); if (err) - return err; + goto done; } - err = diff_output(d3s->diffbuf, "%s\n", + err = diff_output(d3s->diffbuf, "%s%s\n", + line[linelen] == '\n' ? ":" : "", GOT_DIFF_CONFLICT_MARKER_SEP); if (err) - return err; + goto done; } else { - err = diff_output(d3s->diffbuf, "%da\n%s\n", + err = diff_output(d3s->diffbuf, "%da\n:%s\n", d3s->de[n].old.to -1, GOT_DIFF_CONFLICT_MARKER_SEP); if (err) - return err; + goto done; } if (fseeko(d3s->fp[2], d3s->de[n].newo.from, SEEK_SET) - == -1) - return got_error_from_errno("fseek"); - k = (size_t)(d3s->de[n].newo.to - d3s->de[n].newo.from); - for (; k > 0; k -= len) { - size_t r; - len = k > BUFSIZ ? BUFSIZ : k; - r = fread(block, 1, len, d3s->fp[2]); - if (r == 0) { + == -1) { + err = got_error_from_errno("fseek"); + goto done; + } + len = (d3s->de[n].newo.to - d3s->de[n].newo.from); + for (k = 0; k < (ssize_t)len; k += linelen) { + linelen = getline(&line, &linesize, d3s->fp[2]); + if (linelen == -1) { if (feof(d3s->fp[2])) break; - return got_ferror(d3s->fp[2], - GOT_ERR_IO); + err = got_ferror(d3s->fp[2], GOT_ERR_IO); + goto done; } - if (r != len) - len = r; - block[len] = '\0'; - err = diff_output(d3s->diffbuf, "%s", block); + err = diff_output(d3s->diffbuf, ":%s", line); if (err) - return err; + goto done; } if (!d3s->overlap[n]) { err = diff_output(d3s->diffbuf, ".\n"); if (err) - return err; + goto done; } else { - err = diff_output(d3s->diffbuf, "%s\n.\n", d3s->f3mark); + err = diff_output(d3s->diffbuf, "%s%s\n.\n", + line[linelen] == '\n' ? ":" : "", + d3s->f3mark); if (err) - return err; - err = diff_output(d3s->diffbuf, "%da\n%s\n.\n", + goto done; + err = diff_output(d3s->diffbuf, "%da\n:%s\n.\n", d3s->de[n].old.from - 1, d3s->f1mark); if (err) - return err; + goto done; } } - - return NULL; +done: + free(line); + return err; } static const struct got_error * blob - fdd6d5c983d568d8d1d4b48e66ec1d1400a5abea blob + e03fd43fd1cb428c958535c9201a1f65fe2366ad --- regress/cmdline/cherrypick.sh +++ regress/cmdline/cherrypick.sh @@ -1435,7 +1435,7 @@ test_cherrypick_dot_on_a_line_by_itself() { fi (cd $testroot/repo && git checkout -q -b newbranch) - printf "modified\ndelta\n.\non\nbranch\n" > $testroot/repo/gamma/delta + printf "modified\n:delta\n.\non\n:branch\n" > $testroot/repo/gamma/delta git_commit $testroot/repo -m "committing to delta on newbranch" local branch_rev=`git_show_head $testroot/repo` @@ -1452,13 +1452,12 @@ test_cherrypick_dot_on_a_line_by_itself() { return 1 fi - printf "modified\ndelta\n.\non\nbranch\n" > $testroot/content.expected + printf "modified\n:delta\n.\non\n:branch\n" > $testroot/content.expected cat $testroot/wt/gamma/delta > $testroot/content cmp -s $testroot/content.expected $testroot/content ret="$?" if [ "$ret" != "0" ]; then - #diff -u $testroot/content.expected $testroot/content - ret="xfail (badly merged content)" + diff -u $testroot/content.expected $testroot/content fi test_done "$testroot" "$ret" }