From: Tom Jones Subject: diff.git: Fix ed script output To: gameoftrees@openbsd.org Date: Tue, 30 Aug 2022 14:47:58 +0100 Prior to this change ed script output was in the wrong order, i.e. in the order diff_result provides and changes where missing added or changed lines. ed edits need to be in reverse order to keep the edited file in sync --- lib/diff_output_edscript.c | 41 ++++++++++++++++++++++++++++---------- 1 file changed, 30 insertions(+), 11 deletions(-) diff --git a/lib/diff_output_edscript.c b/lib/diff_output_edscript.c index 42d4d5b..3365d90 100644 --- a/lib/diff_output_edscript.c +++ b/lib/diff_output_edscript.c @@ -81,19 +81,34 @@ output_edscript_chunk(struct diff_output_info *outinfo, } } else { /* change */ - if (left_len == 1 && right_len == 1) { - rc = fprintf(dest, "%dc%d\n", left_start, right_start); - } else if (left_len == 1) { - rc = fprintf(dest, "%dc%d,%d\n", left_start, - right_start, cc->right.end); - } else if (right_len == 1) { - rc = fprintf(dest, "%d,%dc%d\n", left_start, - cc->left.end, right_start); + if (left_len == 1) { + rc = fprintf(dest, "%dc\n", left_start); } else { - rc = fprintf(dest, "%d,%dc%d,%d\n", left_start, - cc->left.end, right_start, cc->right.end); + rc = fprintf(dest, "%d,%dc\n", left_start, cc->left.end); + } + } + + /* Now write out the new lines in all the joined chunks. */ + int c_idx; + for (c_idx = cc->chunk.start; c_idx < cc->chunk.end; c_idx++) { + const struct diff_chunk *c = &result->chunks.head[c_idx]; + if (c->left_count && !c->right_count) + continue; + if (c->right_count && !c->left_count) { + rc = diff_output_lines(outinfo, dest, + c->solved ? "" : "?", + c->right_start, c->right_count); + fprintf(dest, ".\n"); + } + if (rc) + return rc; + if (cc->chunk.end == result->chunks.len) { + rc = diff_output_trailing_newline_msg(outinfo, dest, c); + if (rc != DIFF_RC_OK) + return rc; } } + if (rc < 0) return errno; if (outinfo) { @@ -151,7 +166,11 @@ diff_output_edscript(struct diff_output_info **output_info, return DIFF_RC_OK; } - for (i = 0; i < result->chunks.len; i++) { + /* + * Changes in an ed script are in reverse order, the last change to the + * file has to be made first to keep state while making edits. + */ + for (i = result->chunks.len-1; i >= 0 ; i--) { struct diff_chunk *chunk = &result->chunks.head[i]; enum diff_chunk_type t = diff_chunk_type(chunk); struct diff_chunk_context next;