Commit Diff


commit - dffd0deb2bcfd6ec499f8c026c01afd41369b3a6
commit + b67f3bcb5237084aa51e21704775e3df1b159ad0
blob - 1da34c64d7271fbd198a3a0cfc8d0414641d22d8
blob + 0531fabe30530664069034f1c3166fe9d18a6e54
--- lib/diff_atomize_text.c
+++ lib/diff_atomize_text.c
@@ -43,6 +43,7 @@ diff_data_atomize_text_lines_fd(struct diff_data *d)
 	unsigned int array_size_estimate = d->len / 50;
 	unsigned int pow2 = 1;
 	bool ignore_whitespace = (d->diff_flags & DIFF_FLAG_IGNORE_WHITESPACE);
+	bool embedded_nul = false;
 
 	while (array_size_estimate >>= 1)
 		pow2++;
@@ -71,6 +72,8 @@ diff_data_atomize_text_lines_fd(struct diff_data *d)
 					    || !isspace(buf[i]))
 						hash = diff_atom_hash_update(
 						    hash, buf[i]);
+					if (buf[i] == '\0')
+						embedded_nul = true;
 					line_end++;
 				} else
 					eol = buf[i];
@@ -112,6 +115,10 @@ diff_data_atomize_text_lines_fd(struct diff_data *d)
 			return errno;
 	}
 
+	/* File are considered binary if they contain embedded '\0' bytes. */
+	if (embedded_nul)
+		d->atomizer_flags |= DIFF_ATOMIZER_FOUND_BINARY_DATA;
+
 	return DIFF_RC_OK;
 }
 
@@ -121,7 +128,7 @@ diff_data_atomize_text_lines_mmap(struct diff_data *d)
 	const uint8_t *pos = d->data;
 	const uint8_t *end = pos + d->len;
 	bool ignore_whitespace = (d->diff_flags & DIFF_FLAG_IGNORE_WHITESPACE);
-
+	bool embedded_nul = false;
 	unsigned int array_size_estimate = d->len / 50;
 	unsigned int pow2 = 1;
 	while (array_size_estimate >>= 1)
@@ -137,6 +144,8 @@ diff_data_atomize_text_lines_mmap(struct diff_data *d)
 			if (!ignore_whitespace
 			    || !isspace(*line_end))
 				hash = hash * 23 + *line_end;
+			if (*line_end == '\0')
+				embedded_nul = true;
 			line_end++;
 		}
 
@@ -167,6 +176,10 @@ diff_data_atomize_text_lines_mmap(struct diff_data *d)
 		pos = line_end;
 	}
 
+	/* File are considered binary if they contain embedded '\0' bytes. */
+	if (embedded_nul)
+		d->atomizer_flags |= DIFF_ATOMIZER_FOUND_BINARY_DATA;
+
 	return DIFF_RC_OK;
 }
 
blob - bd94a9109c7f29432f6af3217b4a5775f3f0493c
blob + 5e816ae10b5948c0aeacd27365a91f3147b96baf
--- lib/diff_main.h
+++ lib/diff_main.h
@@ -105,6 +105,7 @@ struct diff_data {
 	const uint8_t *data;	/* if memory-mapped */
 	off_t len;
 
+	int atomizer_flags;
 	ARRAYLIST(struct diff_atom) atoms;
 	struct diff_data *root;
 	struct diff_data *current;
@@ -115,8 +116,13 @@ struct diff_data {
 	int err;
 };
 
+/* Flags set by file atomizer. */
+#define DIFF_ATOMIZER_FOUND_BINARY_DATA	0x00000001
+
+/* Flags set by caller of diff_main(). */
 #define DIFF_FLAG_IGNORE_WHITESPACE	0x00000001
 #define DIFF_FLAG_SHOW_PROTOTYPES	0x00000002
+#define DIFF_FLAG_FORCE_TEXT_DATA	0x00000004
 
 void diff_data_free(struct diff_data *diff_data);
 
@@ -143,7 +149,7 @@ struct diff_state;
  *
  * func_data: context pointer (free to be used by implementation).
  * d: struct diff_data with d->data and d->len already set up, and
- * d->atoms to be created.
+ * d->atoms to be created and d->atomizer_flags to be set up.
  */
 typedef int (*diff_atomize_func_t)(void *func_data, struct diff_data *d);
 
blob - 116c0d8c3b0d2a06a61a9f516b6b89dfe3f82f8d
blob + 677f5baf44d4fa746fc192cb95326307b7f2bf0c
--- lib/diff_output_edscript.c
+++ lib/diff_output_edscript.c
@@ -110,6 +110,12 @@ diff_output_edscript(struct diff_output_info **output_
 {
 	struct diff_output_info *outinfo = NULL;
 	struct diff_chunk_context cc = {};
+	int atomizer_flags = (result->left->atomizer_flags|
+	    result->right->atomizer_flags);
+	int flags = (result->left->root->diff_flags |
+	    result->right->root->diff_flags);
+	bool force_text = (flags & DIFF_FLAG_FORCE_TEXT_DATA);
+	bool have_binary = (atomizer_flags & DIFF_ATOMIZER_FOUND_BINARY_DATA);
 	int i, rc;
 
 	if (!result)
@@ -124,6 +130,23 @@ diff_output_edscript(struct diff_output_info **output_
 		outinfo = *output_info;
 	}
 
+	if (have_binary && !force_text) {
+		for (i = 0; i < result->chunks.len; i++) {
+			struct diff_chunk *c = &result->chunks.head[i];
+			enum diff_chunk_type t = diff_chunk_type(c);
+
+			if (t != CHUNK_MINUS && t != CHUNK_PLUS)
+				continue;
+
+			fprintf(dest, "Binary files %s and %s differ\n",
+			    info->left_path ? : "a",
+			    info->right_path ? : "b");
+			break;
+		}
+
+		return DIFF_RC_OK;
+	}
+
 	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);
blob - 2f178e703ce61ba77413863c0b71d0f96e256909
blob + 520dc91d99494e5f4a3c9be8c238a6defd1ff48a
--- lib/diff_output_unidiff.c
+++ lib/diff_output_unidiff.c
@@ -412,9 +412,13 @@ diff_output_unidiff(struct diff_output_info **output_i
 	struct diff_output_unidiff_state *state;
 	struct diff_chunk_context cc = {};
 	struct diff_output_info *outinfo = NULL;
+	int atomizer_flags = (result->left->atomizer_flags|
+	    result->right->atomizer_flags);
 	int flags = (result->left->root->diff_flags |
 	    result->right->root->diff_flags);
 	bool show_function_prototypes = (flags & DIFF_FLAG_SHOW_PROTOTYPES);
+	bool force_text = (flags & DIFF_FLAG_FORCE_TEXT_DATA);
+	bool have_binary = (atomizer_flags & DIFF_ATOMIZER_FOUND_BINARY_DATA);
 	int i;
 
 	if (!result)
@@ -428,7 +432,24 @@ diff_output_unidiff(struct diff_output_info **output_i
 			return ENOMEM;
 		outinfo = *output_info;
 	}
+
+	if (have_binary && !force_text) {
+		for (i = 0; i < result->chunks.len; i++) {
+			struct diff_chunk *c = &result->chunks.head[i];
+			enum diff_chunk_type t = diff_chunk_type(c);
 
+			if (t != CHUNK_MINUS && t != CHUNK_PLUS)
+				continue;
+
+			fprintf(dest, "Binary files %s and %s differ\n",
+			    info->left_path ? : "a",
+			    info->right_path ? : "b");
+			break;
+		}
+
+		return DIFF_RC_OK;
+	}
+
 	state = diff_output_unidiff_state_alloc();
 	if (state == NULL) {
 		if (output_info) {