Commit Diff


commit - b5a3e4d3220d54590de58ecf5a2199285e3f9263
commit + 06b928e23f06a14d0c75544ee5814fde7d801fe0
blob - 239f256775bd901b4c9fe8229d961b6e6708b250
blob + cb905cf4b378e9d869b063bcb70bbfd7ea993c4b
--- Makefile
+++ Makefile
@@ -6,8 +6,6 @@ SRCS= \
 	diff_myers.c \
 	diff_patience.c \
 	diff_output.c \
-	diff_output_plain.c \
-	diff_output_unidiff.c \
 	${END}
 
 .if defined(PROFILE)
blob - 9e92df1e83b5f18049b7152922d5f0d9e0f98f71
blob + f367d0243bf9c2dfbf553ef3a1c63a1e3bb114a2
--- diff_output.c
+++ diff_output.c
@@ -16,10 +16,14 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* Common parts for printing diff output */
-
 #include "diff_main.h"
+#include "debug.h"
 
+
+/*
+ * Common parts for printing diff output
+ */
+
 void
 diff_output_lines(FILE *dest, const char *prefix, struct diff_atom *start_atom, unsigned int count)
 {
@@ -55,3 +59,239 @@ diff_output_info(FILE *dest, const struct diff_input_i
 	    info->right_path ? : "b");
 	return DIFF_RC_OK;
 }
+
+/*
+ * Output all lines of a diff_result.
+ */
+enum diff_rc
+diff_output_plain(FILE *dest, const struct diff_input_info *info,
+    const struct diff_result *result) {
+	if (!result)
+		return DIFF_RC_EINVAL;
+	if (result->rc != DIFF_RC_OK)
+		return result->rc;
+
+	diff_output_info(dest, info);
+
+	int i;
+	for (i = 0; i < result->chunks.len; i++) {
+		struct diff_chunk *c = &result->chunks.head[i];
+		if (c->left_count && c->right_count)
+			diff_output_lines(dest, c->solved ? " " : "?", c->left_start, c->left_count);
+		else if (c->left_count && !c->right_count)
+			diff_output_lines(dest, c->solved ? "-" : "?", c->left_start, c->left_count);
+		else if (c->right_count && !c->left_count)
+			diff_output_lines(dest, c->solved ? "+" : "?", c->right_start, c->right_count);
+	}
+	return DIFF_RC_OK;
+}
+
+enum diff_rc
+diff_plain(FILE *dest, const struct diff_config *diff_config,
+    const struct diff_input_info *info,
+    const char *left, int left_len, const char *right, int right_len)
+{
+	enum diff_rc rc;
+	left_len = left_len < 0 ? strlen(left) : left_len;
+	right_len = right_len < 0 ? strlen(right) : right_len;
+	struct diff_result *result = diff_main(diff_config, left, left_len, right, right_len);
+	rc = diff_output_plain(dest, info, result);
+	diff_result_free(result);
+	return rc;
+}
+
+/*
+ * Produce a unidiff output from a diff_result.
+ */
+enum chunk_type {
+	CHUNK_EMPTY,
+	    CHUNK_PLUS,
+	    CHUNK_MINUS,
+	    CHUNK_SAME,
+	    CHUNK_WEIRD,
+};
+
+static inline enum chunk_type
+chunk_type(const struct diff_chunk *chunk)
+{
+	if (!chunk->left_count && !chunk->right_count)
+		return CHUNK_EMPTY;
+	if (!chunk->solved)
+		return CHUNK_WEIRD;
+	if (!chunk->right_count)
+		return CHUNK_MINUS;
+	if (!chunk->left_count)
+		return CHUNK_PLUS;
+	if (chunk->left_count != chunk->right_count)
+		return CHUNK_WEIRD;
+	return CHUNK_SAME;
+}
+
+struct chunk_context {
+	struct range chunk;
+	struct range left, right;
+};
+
+static bool
+chunk_context_empty(const struct chunk_context *cc)
+{
+	return range_empty(&cc->chunk);
+}
+
+static void
+chunk_context_get(struct chunk_context *cc, const struct diff_result *r, int chunk_idx,
+    int context_lines)
+{
+	const struct diff_chunk *c = &r->chunks.head[chunk_idx];
+	int left_start = diff_atom_root_idx(&r->left, c->left_start);
+	int right_start = diff_atom_root_idx(&r->right, c->right_start);
+
+	*cc = (struct chunk_context){
+		.chunk = {
+			.start = chunk_idx,
+			.end = chunk_idx + 1,
+		},
+		.left = {
+			.start = MAX(0, left_start - context_lines),
+			.end = MIN(r->left.atoms.len, left_start + c->left_count + context_lines),
+		},
+		.right = {
+			.start = MAX(0, right_start - context_lines),
+			.end = MIN(r->right.atoms.len, right_start + c->right_count + context_lines),
+		},
+	};
+}
+
+static bool
+chunk_contexts_touch(const struct chunk_context *cc, const struct chunk_context *other)
+{
+	return ranges_touch(&cc->chunk, &other->chunk) ||
+	    ranges_touch(&cc->left, &other->left) ||
+	    ranges_touch(&cc->right, &other->right);
+}
+
+static void
+chunk_contexts_merge(struct chunk_context *cc, const struct chunk_context *other)
+{
+	ranges_merge(&cc->chunk, &other->chunk);
+	ranges_merge(&cc->left, &other->left);
+	ranges_merge(&cc->right, &other->right);
+}
+
+static void
+diff_output_unidiff_chunk(FILE *dest, bool *info_printed, const struct diff_input_info *info,
+    const struct diff_result *result, const struct chunk_context *cc) {
+	if (range_empty(&cc->left) && range_empty(&cc->right))
+		return;
+
+	if (!(*info_printed)) {
+		diff_output_info(dest, info);
+		*info_printed = true;
+	}
+
+	fprintf(dest, "@@ -%d,%d +%d,%d @@\n",
+	    cc->left.start + 1, cc->left.end - cc->left.start,
+	    cc->right.start + 1, cc->right.end - cc->right.start);
+
+	/* Got the absolute line numbers where to start printing, and the index of the interesting (non-context) chunk.
+	 * To print context lines above the interesting chunk, nipping on the previous chunk index may be necessary.
+	 * It is guaranteed to be only context lines where left == right, so it suffices to look on the left. */
+	const struct diff_chunk *first_chunk = &result->chunks.head[cc->chunk.start];
+	int chunk_start_line = diff_atom_root_idx(&result->left, first_chunk->left_start);
+	if (cc->left.start < chunk_start_line)
+		diff_output_lines(dest, " ", &result->left.atoms.head[cc->left.start],
+		    chunk_start_line - cc->left.start);
+
+	/* Now write out all the joined chunks and contexts between them */
+	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)
+			diff_output_lines(dest, c->solved ? " " : "?", c->left_start, c->left_count);
+		else if (c->left_count && !c->right_count)
+			diff_output_lines(dest, c->solved ? "-" : "?", c->left_start, c->left_count);
+		else if (c->right_count && !c->left_count)
+			diff_output_lines(dest, c->solved ? "+" : "?", c->right_start, c->right_count);
+	}
+
+	/* Trailing context? */
+	const struct diff_chunk *last_chunk = &result->chunks.head[cc->chunk.end - 1];
+	int chunk_end_line = diff_atom_root_idx(&result->left, last_chunk->left_start + last_chunk->left_count);
+	if (cc->left.end > chunk_end_line)
+		diff_output_lines(dest, " ", &result->left.atoms.head[chunk_end_line],
+		    cc->left.end - chunk_end_line);
+}
+
+enum diff_rc
+diff_output_unidiff(FILE *dest, const struct diff_input_info *info,
+    const struct diff_result *result, unsigned int context_lines) {
+	if (!result)
+		return DIFF_RC_EINVAL;
+	if (result->rc != DIFF_RC_OK)
+		return result->rc;
+
+	struct chunk_context cc = {};
+	bool info_printed = false;
+
+	int i;
+	for (i = 0; i < result->chunks.len; i++) {
+		struct diff_chunk *c = &result->chunks.head[i];
+		enum chunk_type t = chunk_type(c);
+
+		if (t == CHUNK_MINUS || t == CHUNK_PLUS) {
+			if (chunk_context_empty(&cc)) {
+				/* These are the first lines being printed.
+				 * Note down the start point, any number of subsequent chunks may be joined up to this
+				 * unidiff chunk by context lines or by being directly adjacent. */
+				chunk_context_get(&cc, result, i, context_lines);
+				debug("new chunk to be printed: chunk %d-%d left %d-%d right %d-%d\n",
+				    cc.chunk.start, cc.chunk.end,
+				    cc.left.start, cc.left.end, cc.right.start, cc.right.end);
+			} else {
+				/* There already is a previous chunk noted down for being printed.
+				 * Does it join up with this one? */
+				struct chunk_context next;
+				chunk_context_get(&next, result, i, context_lines);
+				debug("new chunk to be printed: chunk %d-%d left %d-%d right %d-%d\n",
+				    next.chunk.start, next.chunk.end,
+				    next.left.start, next.left.end, next.right.start, next.right.end);
+				if (chunk_contexts_touch(&cc, &next)) {
+					/* This next context touches or overlaps the previous one, join. */
+					chunk_contexts_merge(&cc, &next);
+					debug("new chunk to be printed touches previous chunk, now: left %d-%d right %d-%d\n",
+					    cc.left.start, cc.left.end, cc.right.start, cc.right.end);
+				} else {
+					/* No touching, so the previous context is complete with a gap between it and
+					 * this next one. Print the previous one and start fresh here. */
+					debug("new chunk to be printed does not touch previous chunk; print left %d-%d right %d-%d\n",
+					    cc.left.start, cc.left.end, cc.right.start, cc.right.end);
+					diff_output_unidiff_chunk(dest, &info_printed, info, result, &cc);
+					cc = next;
+					debug("new unprinted chunk is left %d-%d right %d-%d\n",
+					    cc.left.start, cc.left.end, cc.right.start, cc.right.end);
+				}
+			}
+		}
+
+	}
+
+	if (!chunk_context_empty(&cc))
+		diff_output_unidiff_chunk(dest, &info_printed, info, result, &cc);
+	return DIFF_RC_OK;
+}
+
+enum diff_rc
+diff_unidiff(FILE *dest, const struct diff_config *diff_config,
+    const struct diff_input_info *info,
+    const char *left, int left_len, const char *right, int right_len,
+    unsigned int context_lines)
+{
+	enum diff_rc rc;
+	left_len = left_len < 0 ? strlen(left) : left_len;
+	right_len = right_len < 0 ? strlen(right) : right_len;
+	struct diff_result *result = diff_main(diff_config, left, left_len, right, right_len);
+	rc = diff_output_unidiff(dest, info, result, context_lines);
+	diff_result_free(result);
+	return rc;
+}
blob - 34916d08db89aba7a95acf281e681c11b69bbd4d (mode 644)
blob + /dev/null
--- diff_output_plain.c
+++ /dev/null
@@ -1,58 +0,0 @@
-/*	$OpenBSD$	*/
-
-/*
- * Copyright (c) 2020 Neels Hofmeyr <neels@hofmeyr.de>
- *
- * 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.
- */
-
-/* Output all lines of a diff_result. */
-
-#include "diff_main.h"
-
-enum diff_rc
-diff_output_plain(FILE *dest, const struct diff_input_info *info,
-    const struct diff_result *result) {
-	if (!result)
-		return DIFF_RC_EINVAL;
-	if (result->rc != DIFF_RC_OK)
-		return result->rc;
-
-	diff_output_info(dest, info);
-
-	int i;
-	for (i = 0; i < result->chunks.len; i++) {
-		struct diff_chunk *c = &result->chunks.head[i];
-		if (c->left_count && c->right_count)
-			diff_output_lines(dest, c->solved ? " " : "?", c->left_start, c->left_count);
-		else if (c->left_count && !c->right_count)
-			diff_output_lines(dest, c->solved ? "-" : "?", c->left_start, c->left_count);
-		else if (c->right_count && !c->left_count)
-			diff_output_lines(dest, c->solved ? "+" : "?", c->right_start, c->right_count);
-	}
-	return DIFF_RC_OK;
-}
-
-enum diff_rc
-diff_plain(FILE *dest, const struct diff_config *diff_config,
-    const struct diff_input_info *info,
-    const char *left, int left_len, const char *right, int right_len)
-{
-	enum diff_rc rc;
-	left_len = left_len < 0 ? strlen(left) : left_len;
-	right_len = right_len < 0 ? strlen(right) : right_len;
-	struct diff_result *result = diff_main(diff_config, left, left_len, right, right_len);
-	rc = diff_output_plain(dest, info, result);
-	diff_result_free(result);
-	return rc;
-}
blob - 4596ed14265a10e54dedc012c92f82780602e409 (mode 644)
blob + /dev/null
--- diff_output_unidiff.c
+++ /dev/null
@@ -1,215 +0,0 @@
-/*	$OpenBSD$	*/
-
-/*
- * Copyright (c) 2020 Neels Hofmeyr <neels@hofmeyr.de>
- *
- * 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.
- */
-
-/* Produce a unidiff output from a diff_result. */
-
-#include "diff_main.h"
-#include "debug.h"
-
-enum chunk_type {
-	CHUNK_EMPTY,
-	    CHUNK_PLUS,
-	    CHUNK_MINUS,
-	    CHUNK_SAME,
-	    CHUNK_WEIRD,
-};
-
-static inline enum chunk_type
-chunk_type(const struct diff_chunk *chunk)
-{
-	if (!chunk->left_count && !chunk->right_count)
-		return CHUNK_EMPTY;
-	if (!chunk->solved)
-		return CHUNK_WEIRD;
-	if (!chunk->right_count)
-		return CHUNK_MINUS;
-	if (!chunk->left_count)
-		return CHUNK_PLUS;
-	if (chunk->left_count != chunk->right_count)
-		return CHUNK_WEIRD;
-	return CHUNK_SAME;
-}
-
-struct chunk_context {
-	struct range chunk;
-	struct range left, right;
-};
-
-static bool
-chunk_context_empty(const struct chunk_context *cc)
-{
-	return range_empty(&cc->chunk);
-}
-
-static void
-chunk_context_get(struct chunk_context *cc, const struct diff_result *r, int chunk_idx,
-    int context_lines)
-{
-	const struct diff_chunk *c = &r->chunks.head[chunk_idx];
-	int left_start = diff_atom_root_idx(&r->left, c->left_start);
-	int right_start = diff_atom_root_idx(&r->right, c->right_start);
-
-	*cc = (struct chunk_context){
-		.chunk = {
-			.start = chunk_idx,
-			.end = chunk_idx + 1,
-		},
-		.left = {
-			.start = MAX(0, left_start - context_lines),
-			.end = MIN(r->left.atoms.len, left_start + c->left_count + context_lines),
-		},
-		.right = {
-			.start = MAX(0, right_start - context_lines),
-			.end = MIN(r->right.atoms.len, right_start + c->right_count + context_lines),
-		},
-	};
-}
-
-static bool
-chunk_contexts_touch(const struct chunk_context *cc, const struct chunk_context *other)
-{
-	return ranges_touch(&cc->chunk, &other->chunk) ||
-	    ranges_touch(&cc->left, &other->left) ||
-	    ranges_touch(&cc->right, &other->right);
-}
-
-static void
-chunk_contexts_merge(struct chunk_context *cc, const struct chunk_context *other)
-{
-	ranges_merge(&cc->chunk, &other->chunk);
-	ranges_merge(&cc->left, &other->left);
-	ranges_merge(&cc->right, &other->right);
-}
-
-static void
-diff_output_unidiff_chunk(FILE *dest, bool *info_printed, const struct diff_input_info *info,
-    const struct diff_result *result, const struct chunk_context *cc) {
-	if (range_empty(&cc->left) && range_empty(&cc->right))
-		return;
-
-	if (!(*info_printed)) {
-		diff_output_info(dest, info);
-		*info_printed = true;
-	}
-
-	fprintf(dest, "@@ -%d,%d +%d,%d @@\n",
-	    cc->left.start + 1, cc->left.end - cc->left.start,
-	    cc->right.start + 1, cc->right.end - cc->right.start);
-
-	/* Got the absolute line numbers where to start printing, and the index of the interesting (non-context) chunk.
-	 * To print context lines above the interesting chunk, nipping on the previous chunk index may be necessary.
-	 * It is guaranteed to be only context lines where left == right, so it suffices to look on the left. */
-	const struct diff_chunk *first_chunk = &result->chunks.head[cc->chunk.start];
-	int chunk_start_line = diff_atom_root_idx(&result->left, first_chunk->left_start);
-	if (cc->left.start < chunk_start_line)
-		diff_output_lines(dest, " ", &result->left.atoms.head[cc->left.start],
-		    chunk_start_line - cc->left.start);
-
-	/* Now write out all the joined chunks and contexts between them */
-	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)
-			diff_output_lines(dest, c->solved ? " " : "?", c->left_start, c->left_count);
-		else if (c->left_count && !c->right_count)
-			diff_output_lines(dest, c->solved ? "-" : "?", c->left_start, c->left_count);
-		else if (c->right_count && !c->left_count)
-			diff_output_lines(dest, c->solved ? "+" : "?", c->right_start, c->right_count);
-	}
-
-	/* Trailing context? */
-	const struct diff_chunk *last_chunk = &result->chunks.head[cc->chunk.end - 1];
-	int chunk_end_line = diff_atom_root_idx(&result->left, last_chunk->left_start + last_chunk->left_count);
-	if (cc->left.end > chunk_end_line)
-		diff_output_lines(dest, " ", &result->left.atoms.head[chunk_end_line],
-		    cc->left.end - chunk_end_line);
-}
-
-enum diff_rc
-diff_output_unidiff(FILE *dest, const struct diff_input_info *info,
-    const struct diff_result *result, unsigned int context_lines) {
-	if (!result)
-		return DIFF_RC_EINVAL;
-	if (result->rc != DIFF_RC_OK)
-		return result->rc;
-
-	struct chunk_context cc = {};
-	bool info_printed = false;
-
-	int i;
-	for (i = 0; i < result->chunks.len; i++) {
-		struct diff_chunk *c = &result->chunks.head[i];
-		enum chunk_type t = chunk_type(c);
-
-		if (t == CHUNK_MINUS || t == CHUNK_PLUS) {
-			if (chunk_context_empty(&cc)) {
-				/* These are the first lines being printed.
-				 * Note down the start point, any number of subsequent chunks may be joined up to this
-				 * unidiff chunk by context lines or by being directly adjacent. */
-				chunk_context_get(&cc, result, i, context_lines);
-				debug("new chunk to be printed: chunk %d-%d left %d-%d right %d-%d\n",
-				    cc.chunk.start, cc.chunk.end,
-				    cc.left.start, cc.left.end, cc.right.start, cc.right.end);
-			} else {
-				/* There already is a previous chunk noted down for being printed.
-				 * Does it join up with this one? */
-				struct chunk_context next;
-				chunk_context_get(&next, result, i, context_lines);
-				debug("new chunk to be printed: chunk %d-%d left %d-%d right %d-%d\n",
-				    next.chunk.start, next.chunk.end,
-				    next.left.start, next.left.end, next.right.start, next.right.end);
-				if (chunk_contexts_touch(&cc, &next)) {
-					/* This next context touches or overlaps the previous one, join. */
-					chunk_contexts_merge(&cc, &next);
-					debug("new chunk to be printed touches previous chunk, now: left %d-%d right %d-%d\n",
-					    cc.left.start, cc.left.end, cc.right.start, cc.right.end);
-				} else {
-					/* No touching, so the previous context is complete with a gap between it and
-					 * this next one. Print the previous one and start fresh here. */
-					debug("new chunk to be printed does not touch previous chunk; print left %d-%d right %d-%d\n",
-					    cc.left.start, cc.left.end, cc.right.start, cc.right.end);
-					diff_output_unidiff_chunk(dest, &info_printed, info, result, &cc);
-					cc = next;
-					debug("new unprinted chunk is left %d-%d right %d-%d\n",
-					    cc.left.start, cc.left.end, cc.right.start, cc.right.end);
-				}
-			}
-		}
-
-	}
-
-	if (!chunk_context_empty(&cc))
-		diff_output_unidiff_chunk(dest, &info_printed, info, result, &cc);
-	return DIFF_RC_OK;
-}
-
-enum diff_rc
-diff_unidiff(FILE *dest, const struct diff_config *diff_config,
-    const struct diff_input_info *info,
-    const char *left, int left_len, const char *right, int right_len,
-    unsigned int context_lines)
-{
-	enum diff_rc rc;
-	left_len = left_len < 0 ? strlen(left) : left_len;
-	right_len = right_len < 0 ? strlen(right) : right_len;
-	struct diff_result *result = diff_main(diff_config, left, left_len, right, right_len);
-	rc = diff_output_unidiff(dest, info, result, context_lines);
-	diff_result_free(result);
-	return rc;
-}