Commit Diff


commit - 3c72fc1f8c4e7379f78689017df9a129d6ad9b88
commit + 654951e121a78b702156603211659be2c6137182
blob - efb105889ccc3062ecac11fcae439ab59226271c
blob + d049b642d93d3a99f2fdda9a788f9d1365949a16
--- diff.1
+++ diff.1
@@ -23,8 +23,7 @@
 .Nd compare files
 .Sh SYNOPSIS
 .Nm diff
-.Op Fl u
-.Op Fl U Ar number
+.Op Fl c | u | Fl C Ar n | Fl U Ar n
 .Ar file1 file2
 .Sh DESCRIPTION
 The
@@ -37,14 +36,22 @@ line by line.
 .Pp
 The options are as follows:
 .Bl -tag -width Ds
-.It Fl u
-Produces a unified diff with 3 lines of context.
-.It Fl U Ar number
+.It Fl C Ar n
 Similar to
+.Fl c
+with
+.Ar n
+lines of context.
+.It Fl c
+Produces a diff with 3 lines of context.
+.It Fl U Ar n
+Similar to
 .Fl u
 with
-.Ar number
+.Ar n
 lines of context.
+.It Fl u
+Produces a unified diff with 3 lines of context.
 .El
 .Sh EXIT STATUS
 The
blob - 176909cbcc2d9cf0db227ab76310509e550f0745
blob + 1c62a7f5efa616133362b0a161ce18fff5172b82
--- diff.c
+++ diff.c
@@ -23,6 +23,7 @@
 #include <sys/mman.h>
 #include <sys/stat.h>
 
+#include <assert.h>
 #include <err.h>
 #include <fcntl.h>
 #include <limits.h>
@@ -36,12 +37,17 @@
 
 #define DEFAULT_CONTEXT	3
 
-#define F_UNIFIED	(1 << 0)
+#define F_CFORMAT	(1 << 0)
+#define F_FFORMAT	(1 << 1)
+#define F_ED		(1 << 2)
+#define F_UNIFIED	(1 << 3)
 
 struct output_info {
 	const char *left_path;
+	time_t left_time;
 	const char *right_path;
-	int flags;
+	time_t right_time;
+	int format;
 	int context;
 };
 
@@ -84,19 +90,35 @@ const struct diff_config diff_config = {
 __dead void
 usage(void)
 {
-	fprintf(stderr, "usage: %s file1 file2\n", getprogname());
+	fprintf(stderr, "usage: %s [-c | -e | -f | -u] file1 file2\n",
+	    getprogname());
 	exit(1);
 }
 
 int
 main(int argc, char *argv[])
 {
-	int ch, context = DEFAULT_CONTEXT, flags = 0;
+	int ch, context = DEFAULT_CONTEXT, format = 0;
 	long lval;
 	char *ep;
 
-	while ((ch = getopt(argc, argv, "uU:")) != -1) {
+	while ((ch = getopt(argc, argv, "cC:efuU:")) != -1) {
 		switch (ch) {
+		case 'C':
+			lval = strtol(optarg, &ep, 10);
+			if (*ep != '\0' || lval < 0 || lval >= INT_MAX)
+				usage();
+			context = (int)lval;
+			/* FALLTHROUGH */
+		case 'c':
+			format = F_CFORMAT;
+			break;
+		case 'e':
+			format = F_ED;
+			break;
+		case 'f':
+			format = F_FFORMAT;
+			break;
 		case 'U':
 			lval = strtol(optarg, &ep, 10);
 			if (*ep != '\0' || lval < 0 || lval >= INT_MAX)
@@ -104,7 +126,7 @@ main(int argc, char *argv[])
 			context = (int)lval;
 			/* FALLTHROUGH */
 		case 'u':
-			flags |= F_UNIFIED;
+			format = F_UNIFIED;
 			break;
 		default:
 			usage();
@@ -117,13 +139,13 @@ main(int argc, char *argv[])
 	if (argc != 2)
 		usage();
 
-	return diffreg(argv[0], argv[1], flags, context);
+	return diffreg(argv[0], argv[1], format, context);
 }
 
 int
 diffreg(char *file1, char *file2, int flags, int context)
 {
-	struct output_info info = { file1, file2, flags, context };
+	struct output_info info = { file1, 0, file2, 0, flags, context };
 	char *str1, *str2;
 	struct stat st1, st2;
 	struct diff_result *result;
@@ -137,6 +159,8 @@ diffreg(char *file1, char *file2, int flags, int conte
 	if (result->rc != DIFF_RC_OK)
 		return result->rc;
 
+	info.left_time = st1.st_mtime;
+	info.right_time = st2.st_mtime;
 	output(&info, result);
 
 	diff_result_free(result);
@@ -245,8 +269,13 @@ chunk_context_get(struct chunk_context *cc, const stru
 	int left_start, right_start;
 	int context_lines = 0;
 
-	if (info->flags & F_UNIFIED)
+	switch (info->format) {
+	case F_CFORMAT:
+	case F_UNIFIED:
 		context_lines = info->context;
+	default:
+		break;
+	}
 
 	left_start = DD_ROOT_INDEX(&r->left, c->left_start);
 	right_start = DD_ROOT_INDEX(&r->right, c->right_start);
@@ -286,33 +315,78 @@ chunk_context_merge(struct chunk_context *cc, const st
 }
 
 static void
-print_chunk(bool *header_printed, const struct output_info *info,
+print_default(const struct output_info *info,
     const struct diff_result *result, const struct chunk_context *cc)
 {
-	const struct diff_chunk *first_chunk, *last_chunk;
-	int chunk_start_line, chunk_end_line, c_idx;
-	char *minus, *plus;
+	int c_idx;
 
-	if (range_empty(&cc->left) && range_empty(&cc->right))
+	printf("%dc%d\n", cc->left.start + 1, cc->right.start + 1);
+
+	/* Now write out all the joined chunks and contexts between them */
+	for (c_idx = cc->chunk.start; c_idx < cc->chunk.end; c_idx++) {
+		const struct diff_chunk *c = &result->chunks.head[c_idx];
+
+		assert(c->solved);
+
+		if (c->left_count && !c->right_count) {
+			print_lines("< ", c->left_start, c->left_count);
+			continue;
+		}
+
+		if (c->right_count && !c->left_count) {
+			print_lines("> ", c->right_start, c->right_count);
+			continue;
+		}
+	}
+}
+
+void
+print_context_before(const char *prefix, const struct diff_result *result,
+    const struct chunk_context *cc)
+{
+	const struct diff_chunk *chunk = &result->chunks.head[cc->chunk.start];
+	int start_line;
+
+	start_line = DD_ROOT_INDEX(&result->left, chunk->left_start);
+	if (cc->left.start >= start_line)
 		return;
+	print_lines(prefix, DD_ATOM_AT(&result->left, cc->left.start),
+	    start_line - cc->left.start);
+}
 
-	if (!(*header_printed) && info->flags & F_UNIFIED) {
-		printf("--- %s\n+++ %s\n",
-		    info->left_path ? : "a", info->right_path ? : "b");
+void
+print_context_after(const char *prefix, const struct diff_result *result,
+    const struct chunk_context *cc)
+{
+	const struct diff_chunk *chunk = &result->chunks.head[cc->chunk.end - 1];
+	int end_line;
+
+	end_line = DD_ROOT_INDEX(&result->left,
+	    chunk->left_start + chunk->left_count);
+	if (cc->left.end <= end_line)
+		return;
+	print_lines(prefix, DD_ATOM_AT(&result->left, end_line),
+	    cc->left.end - end_line);
+}
+
+static void
+print_unified(bool *header_printed, const struct output_info *info,
+    const struct diff_result *result, const struct chunk_context *cc)
+{
+	int c_idx;
+
+	assert(info->format == F_UNIFIED);
+
+	if (!(*header_printed)) {
+		printf("--- %s\t%s+++ %s\t%s",
+		    info->left_path, ctime(&info->left_time),
+		    info->right_path, ctime(&info->right_time));
 		*header_printed = true;
 	}
 
-	if (info->flags & F_UNIFIED) {
-		minus = "-";
-		plus = "+";
-		printf("@@ -%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);
-	} else {
-		minus = "< ";
-		plus = "> ";
-		printf("%dc%d\n", cc->left.start + 1, cc->right.start + 1);
-	}
+	printf("@@ -%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
@@ -322,38 +396,103 @@ print_chunk(bool *header_printed, const struct output_
 	 * It is guaranteed to be only context lines where left == right,
 	 * so it suffices to look on the left.
 	 */
-	first_chunk = &result->chunks.head[cc->chunk.start];
-	chunk_start_line = DD_ROOT_INDEX(&result->left,
-	    first_chunk->left_start);
+	print_context_before(" ", result, cc);
 
-	if (cc->left.start < chunk_start_line)
-		print_lines(" ", DD_ATOM_AT(&result->left, cc->left.start),
-		    chunk_start_line - cc->left.start);
-
 	/* Now write out all the joined chunks and contexts between them */
 	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)
-			print_lines(c->solved ? " " : "?",
-			    c->left_start, c->left_count);
-		else if (c->left_count && !c->right_count)
-			print_lines(c->solved ? minus : "?",
-			    c->left_start, c->left_count);
-		else if (c->right_count && !c->left_count)
-			print_lines(c->solved ? plus : "?",
-			    c->right_start, c->right_count);
+		assert(c->solved);
+
+		if (c->left_count && c->right_count) {
+			print_lines(" ", c->left_start, c->left_count);
+			continue;
+		}
+
+		if (c->left_count && !c->right_count) {
+			print_lines("-", c->left_start, c->left_count);
+			continue;
+		}
+
+		if (c->right_count && !c->left_count) {
+			print_lines("+", c->right_start, c->right_count);
+			continue;
+		}
 	}
 
 	/* Trailing context? */
-	last_chunk = &result->chunks.head[cc->chunk.end - 1];
-	chunk_end_line = DD_ROOT_INDEX(&result->left,
-	    last_chunk->left_start + last_chunk->left_count);
-	if (cc->left.end > chunk_end_line)
-		print_lines(" ", DD_ATOM_AT(&result->left, chunk_end_line),
-		    cc->left.end - chunk_end_line);
+	print_context_after(" ", result, cc);
 }
 
+static void
+print_cformat(bool *header_printed, const struct output_info *info,
+    const struct diff_result *result, const struct chunk_context *cc)
+{
+	const struct diff_chunk *c, *cleft = NULL, *cright = NULL;
+	int c_idx;
+
+	assert(info->format == F_CFORMAT);
+
+	if (!(*header_printed)) {
+		printf("*** %s\t%s--- %s\t%s",
+		    info->left_path, ctime(&info->left_time),
+		    info->right_path, ctime(&info->right_time));
+		*header_printed = true;
+	}
+
+	for (c_idx = cc->chunk.start; c_idx < cc->chunk.end; c_idx++) {
+		c = &result->chunks.head[c_idx];
+
+		assert(c->solved);
+		if (c->left_count && !c->right_count) {
+			cleft = c;
+			continue;
+		}
+		if (c->right_count && !c->left_count) {
+			cright = c;
+			continue;
+		}
+	}
+
+	printf("***************\n");
+	printf("*** %d,%d ****\n", cc->left.start + 1, cc->left.end);
+	if (cleft != NULL) {
+		print_context_before("  ", result, cc);
+		print_lines(cright ? "! " : "- ",
+		    cleft->left_start, cleft->left_count);
+		print_context_after("  ", result, cc);
+	}
+	printf("--- %d,%d ----\n", cc->right.start + 1, cc->right.end);
+	if (cright != NULL) {
+		print_context_before("  ", result, cc);
+		print_lines(cleft ? "! " : "+ ",
+		    cright->right_start, cright->right_count);
+		print_context_after("  ", result, cc);
+	}
+}
+
+static void
+print_chunk(bool *header_printed, const struct output_info *info,
+    const struct diff_result *result, const struct chunk_context *cc)
+{
+	if (range_empty(&cc->left) && range_empty(&cc->right))
+		return;
+
+	switch (info->format) {
+	case F_UNIFIED:
+		print_unified(header_printed, info, result, cc);
+		break;
+	case F_CFORMAT:
+		print_cformat(header_printed, info, result, cc);
+		break;
+	case F_FFORMAT:
+	case F_ED:
+	default:
+		print_default(info, result, cc);
+		break;
+	}
+}
+
 void
 output(const struct output_info *info, const struct diff_result *result)
 {
blob - 7a63e8958713ab55fbb7ebf87ebe4dd11663e85e
blob + 1a0af62af8fb78b8855e4897f6289fe028b77335
--- diff_atomize_text.c
+++ diff_atomize_text.c
@@ -24,17 +24,17 @@
 #include "diff_main.h"
 
 static int
-diff_data_atomize_text_lines(struct diff_data *d)
+diff_data_atomize_text_lines(struct diff_data *dd)
 {
-	const uint8_t *pos = d->data;
-	const uint8_t *end = pos + d->dlen;
-	unsigned int array_size_estimate = d->dlen / 50;
+	const uint8_t *pos = dd->data;
+	const uint8_t *end = pos + dd->dlen;
+	unsigned int array_size_estimate = dd->dlen / 50;
 	unsigned int pow2 = 1;
 
 	while (array_size_estimate >>= 1)
 		pow2++;
 
-	ARRAYLIST_INIT(d->atoms, 1 << pow2);
+	ARRAYLIST_INIT(dd->atoms, 1 << pow2);
 
 	while (pos < end) {
 		const uint8_t *line_end = pos;
@@ -58,7 +58,7 @@ diff_data_atomize_text_lines(struct diff_data *d)
 			line_end++;
 
 		/* Record the found line as diff atom */
-		ARRAYLIST_ADD(atom, d->atoms);
+		ARRAYLIST_ADD(atom, dd->atoms);
 		if (atom == NULL)
 			return DIFF_RC_ENOMEM;
 
blob - 1a556f7d0464e0bb4e03a1fa3ce0b45209e09ae9
blob + 4affcbb6ab54c059d6b75ca5b2a6937e0ed3e59f
--- diff_main.c
+++ diff_main.c
@@ -68,12 +68,12 @@ diff_state_add_chunk(struct diff_state *state, bool so
 }
 
 void
-diff_data_init_root(struct diff_data *d, const uint8_t *data, size_t dlen)
+diff_data_init_root(struct diff_data *dd, const uint8_t *data, size_t dlen)
 {
-	*d = (struct diff_data) {
+	*dd = (struct diff_data) {
 		.data = data,
 		.dlen = dlen,
-		.root = d,
+		.root = dd,
 	};
 }