Commit Diff


commit - 0c9a7e9d9f2c0efc643a722ca46b8144fadf531f
commit + b7ba71f0ee2562b0d5877b72d4de351a8e78a119
blob - 918cc0e92e3b84fb7583803f03d886355ceb6c5a
blob + 82af7ac31f556849d0d60cf77d5570d2d911e6b4
--- diff/Makefile
+++ diff/Makefile
@@ -12,6 +12,7 @@ SRCS= \
 	diff_output.c \
 	diff_output_plain.c \
 	diff_output_unidiff.c \
+	diff_output_edscript.c \
 	${END}
 MAN =	${PROG}.1
 
blob - 1bf72dd40864c6752c57ff4ca4ff782b973d8768
blob + 33779b232e5c0a49cb587d8763bf9deb96411d0d
--- diff/diff.c
+++ diff/diff.c
@@ -34,7 +34,7 @@
 #include <diff_output.h>
 
 __dead void	 usage(void);
-int		 diffreg(char *, char *, bool, bool, int);
+int		 diffreg(char *, char *, bool, bool, int, bool);
 FILE *		 openfile(const char *, char **, struct stat *);
 
 __dead void
@@ -56,6 +56,7 @@ main(int argc, char *argv[])
 {
 	int ch, rc;
 	bool do_patience = false, ignore_whitespace = false;
+	bool edscript = false;
 	int context_lines = 3;
 
 	while ((ch = getopt(argc, argv, "pwU:e")) != -1) {
@@ -69,6 +70,9 @@ main(int argc, char *argv[])
 		case 'U':
 			context_lines = atoi(optarg);
 			break;
+		case 'e':
+			edscript = true;
+			break;
 		default:
 			usage();
 		}
@@ -81,7 +85,7 @@ main(int argc, char *argv[])
 		usage();
 
 	rc = diffreg(argv[0], argv[1], do_patience, ignore_whitespace,
-	    context_lines);
+	    context_lines, edscript);
 	if (rc != DIFF_RC_OK) {
 		fprintf(stderr, "diff: %s\n", strerror(rc));
 		return 1;
@@ -134,7 +138,7 @@ const struct diff_config diff_config_patience = {
 
 int
 diffreg(char *file1, char *file2, bool do_patience, bool ignore_whitespace,
-    int context_lines)
+    int context_lines, bool edscript)
 {
 	char *str1, *str2;
 	FILE *f1, *f2;
@@ -161,7 +165,12 @@ diffreg(char *file1, char *file2, bool do_patience, bo
 #if 0
 	rc = diff_output_plain(stdout, &info, result);
 #else
-	rc = diff_output_unidiff(NULL, stdout, &info, result, context_lines);
+	if (edscript)
+		rc = diff_output_edscript(NULL, stdout, &info, result);
+	else {
+		rc = diff_output_unidiff(NULL, stdout, &info, result,
+		    context_lines);
+	}
 #endif
 	diff_result_free(result);
 
blob - 20767052a7fd8ba51f93706796155ffdbfb04a82
blob + eb5ea9058a20bee4cbe0ab59e51b057ac8067878
--- include/diff_output.h
+++ include/diff_output.h
@@ -43,6 +43,9 @@ int diff_output_unidiff(struct diff_output_info **outp
 			FILE *dest, const struct diff_input_info *info,
 			const struct diff_result *result,
 			unsigned int context_lines);
+int diff_output_edscript(struct diff_output_info **output_info,
+			 FILE *dest, const struct diff_input_info *info,
+			 const struct diff_result *result);
 int diff_chunk_get_left_start(const struct diff_chunk *c,
 			      const struct diff_result *r,
 			      int context_lines);
blob - 8bc527e0f06aeeca1e930f349552b5503cdae9c8
blob + 0549afc893dd068df20d061b9a9cc67d1251a9da
--- lib/GNUmakefile
+++ lib/GNUmakefile
@@ -6,6 +6,7 @@ SRCS = \
 	diff_output.c \
 	diff_output_plain.c \
 	diff_output_unidiff.c \
+	diff_output_edscript.c \
 	$(END)
 
 # Compat sources
blob - /dev/null
blob + 4ee960cab7a4020d7f2a8ed9b40e0a1bc9ae768a (mode 644)
--- /dev/null
+++ lib/diff_output_edscript.c
@@ -0,0 +1,125 @@
+/* Produce ed(1) script output from a diff_result. */
+/*
+ * Copyright (c) 2020 Neels Hofmeyr <neels@hofmeyr.de>
+ * Copyright (c) 2020 Stefan Sperling <stsp@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+
+#include <arraylist.h>
+#include <diff_main.h>
+#include <diff_output.h>
+
+#include "diff_internal.h"
+
+static int
+output_edscript_chunk(struct diff_output_info *outinfo,
+    FILE *dest, const struct diff_input_info *info,
+    const struct diff_result *result,
+    struct diff_chunk_context *cc, enum diff_chunk_type chunk_type)
+{
+	off_t outoff = 0, *offp;
+	int left_start, left_len, right_start, right_len;
+	int rc;
+
+	left_len = cc->left.end - cc->left.start;
+	if (left_len < 0)
+		return EINVAL;
+	else if (left_len == 0 && cc->left.start > 0)
+		left_start = cc->left.start;
+	else
+		left_start = cc->left.start + 1;
+
+	right_len = cc->right.end - cc->right.start;
+	if (right_len < 0)
+		return EINVAL;
+	else if (right_len == 0 && cc->right.start > 0)
+		right_start = cc->right.start;
+	else
+		right_start = cc->right.start + 1;
+
+	if (chunk_type == CHUNK_MINUS) {
+		if (left_len == 1) {
+			rc = fprintf(dest, "%dd%d", left_start, right_start);
+		} else {
+			rc = fprintf(dest, "%d,%dd%d\n", left_start,
+			    cc->left.end, right_start);
+		}
+	} else if (chunk_type == CHUNK_PLUS) {
+		if (right_len == 1) {
+			rc = fprintf(dest, "%da%d\n", left_start, right_start);
+		} else {
+			rc = fprintf(dest, "%da%d,%d\n", left_start,
+			    right_start, cc->right.end);
+		}
+	} else
+		return EINVAL;
+
+	if (rc < 0)
+		return errno;
+	if (outinfo) {
+		ARRAYLIST_ADD(offp, outinfo->line_offsets);
+		if (offp == NULL)
+			return ENOMEM;
+		outoff += rc;
+		*offp = outoff;
+	}
+
+	return DIFF_RC_OK;
+}
+
+int
+diff_output_edscript(struct diff_output_info **output_info,
+    FILE *dest, const struct diff_input_info *info,
+    const struct diff_result *result)
+{
+	struct diff_output_info *outinfo = NULL;
+	int i, rc;
+
+	if (!result)
+		return EINVAL;
+	if (result->rc != DIFF_RC_OK)
+		return result->rc;
+
+	if (output_info) {
+		*output_info = diff_output_info_alloc();
+		if (*output_info == NULL)
+			return ENOMEM;
+		outinfo = *output_info;
+	}
+
+	for (i = 0; i < result->chunks.len; i++) {
+		struct diff_chunk *chunk = &result->chunks.head[i];
+		enum diff_chunk_type t = diff_chunk_type(chunk);
+		struct diff_chunk_context cc = {};
+
+		if (t != CHUNK_MINUS && t != CHUNK_PLUS)
+			continue;
+
+		diff_chunk_context_get(&cc, result, i, 0);
+
+		if (diff_range_empty(&cc.chunk))
+			continue;
+
+		rc = output_edscript_chunk(outinfo, dest, info, result, &cc, t);
+		if (rc != DIFF_RC_OK)
+			return rc;
+	}
+
+	return DIFF_RC_OK;
+}