Commit Diff


commit - 5ed6e4d2a7519005ddb8c8b7f47a02f6085df3fe
commit + 13e2caa3edcc68a62e29b4d5503254cd5bf80b2b
blob - 0bcda3a003c8741c8ea2e2801503387eb993bd12
blob + 6bd48428c4f92c5ed7c7d1695af2f866b953cefb
--- diff/diff.c
+++ diff/diff.c
@@ -41,15 +41,17 @@ enum diffreg_algo {
 };
 
 __dead void	 usage(void);
-int		 diffreg(char *, char *, enum diffreg_algo, bool, int, bool);
+int		 diffreg(char *, char *, enum diffreg_algo, bool, bool,
+			 int, bool);
 FILE *		 openfile(const char *, char **, struct stat *);
 
 __dead void
 usage(void)
 {
 	fprintf(stderr,
-		"usage: %s [-PQTwe] [-U n] file1 file2\n"
+		"usage: %s [-pPQTwe] [-U n] file1 file2\n"
 		"\n"
+		"  -p   Show function prototypes in hunk headers\n"
 		"  -P   Use Patience Diff (slower but often nicer)\n"
 		"  -Q   Use forward-Myers for small files, otherwise Patience\n"
 		"  -T   Trivial algo: detect similar start and end only\n"
@@ -65,12 +67,16 @@ main(int argc, char *argv[])
 {
 	int ch, rc;
 	bool ignore_whitespace = false;
+	bool show_function_prototypes = false;
 	bool edscript = false;
 	int context_lines = 3;
 	enum diffreg_algo algo = DIFFREG_ALGO_MYERS_THEN_MYERS_DIVIDE;
 
-	while ((ch = getopt(argc, argv, "PQTwU:e")) != -1) {
+	while ((ch = getopt(argc, argv, "pPQTwU:e")) != -1) {
 		switch (ch) {
+		case 'p':
+			show_function_prototypes = true;
+			break;
 		case 'P':
 			algo = DIFFREG_ALGO_PATIENCE;
 			break;
@@ -101,7 +107,7 @@ main(int argc, char *argv[])
 		usage();
 
 	rc = diffreg(argv[0], argv[1], algo, ignore_whitespace,
-	    context_lines, edscript);
+	    show_function_prototypes, context_lines, edscript);
 	if (rc != DIFF_RC_OK) {
 		fprintf(stderr, "diff: %s\n", strerror(rc));
 		return 1;
@@ -173,7 +179,7 @@ const struct diff_config diff_config_no_algo = {
 
 int
 diffreg(char *file1, char *file2, enum diffreg_algo algo, bool ignore_whitespace,
-    int context_lines, bool edscript)
+    bool show_function_prototypes, int context_lines, bool edscript)
 {
 	char *str1, *str2;
 	FILE *f1, *f2;
@@ -208,6 +214,8 @@ diffreg(char *file1, char *file2, enum diffreg_algo al
 
 	if (ignore_whitespace)
 		diff_flags |= DIFF_FLAG_IGNORE_WHITESPACE;
+	if (show_function_prototypes)
+		diff_flags |= DIFF_FLAG_SHOW_PROTOTYPES;
 
 	result = diff_main(cfg, f1, str1, st1.st_size, f2, str2, st2.st_size,
 	    diff_flags);
blob - f49a6893b6847f02d5127764222375f1184d051d
blob + 99669105d130b9e49ecf3ba09743e0e2c8b1e031
--- include/diff_main.h
+++ include/diff_main.h
@@ -51,6 +51,7 @@ struct diff_data {
 };
 
 #define DIFF_FLAG_IGNORE_WHITESPACE	0x00000001
+#define DIFF_FLAG_SHOW_PROTOTYPES	0x00000002
 
 void diff_data_free(struct diff_data *diff_data);
 
blob - f48c869ab05318ba318a42e11631e120cedb7cb6
blob + e4d0d0f911a91395f8dd56ae7de181ff081cfbdf
--- lib/diff_internal.h
+++ lib/diff_internal.h
@@ -115,6 +115,13 @@ diff_atom_same(bool *same,
 	     && ((ATOM) - (DIFF_DATA)->atoms.head < (DIFF_DATA)->atoms.len); \
 	     (ATOM)++)
 
+#define diff_data_foreach_atom_backwards_from(FROM, ATOM, DIFF_DATA) \
+	for ((ATOM) = (FROM); \
+	     (ATOM) \
+	     && ((ATOM) >= (DIFF_DATA)->atoms.head) \
+	     && ((ATOM) - (DIFF_DATA)->atoms.head >= 0); \
+	     (ATOM)--)
+
 /* A diff chunk represents a set of atoms on the left and/or a set of atoms on
  * the right.
  *
@@ -222,6 +229,9 @@ int diff_output_lines(struct diff_output_info *output_
 int diff_output_trailing_newline_msg(struct diff_output_info *outinfo,
 				     FILE *dest,
 				     const struct diff_chunk *c);
+int diff_output_match_function_prototype(char **prototype,
+					 const struct diff_result *result,
+					 const struct diff_chunk_context *cc);
 
 struct diff_output_info *diff_output_info_alloc(void);
 
blob - 8832026c2c75b90807d7a10e032484e14cc4efd6
blob + 5101e49206dbcf9bfcd8df71242aec39ed8f57a0
--- lib/diff_output.c
+++ lib/diff_output.c
@@ -15,11 +15,13 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
+#include <ctype.h>
 #include <errno.h>
 #include <inttypes.h>
 #include <stdbool.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
 #include <unistd.h>
 
 #include <arraylist.h>
@@ -233,6 +235,57 @@ diff_output_trailing_newline_msg(struct diff_output_in
 	return DIFF_RC_OK;
 }
 
+static bool
+is_function_prototype(const char *buf)
+{
+	return isalpha(buf[0]) || buf[0] == '_' || buf[0] == '$';
+}
+
+#define FUNCTION_CONTEXT_SIZE	55
+
+int
+diff_output_match_function_prototype(char **prototype,
+    const struct diff_result *result,
+    const struct diff_chunk_context *cc)
+{
+	struct diff_atom *start_atom, *atom;
+	const struct diff_data *data;
+	unsigned char buf[FUNCTION_CONTEXT_SIZE];
+	int rc, i;
+
+	*prototype = NULL;
+
+	if (result->left.atoms.len > 0) {
+		data = &result->left;
+		start_atom = &data->atoms.head[cc->left.start];
+	} else if (result->right.atoms.len > 0) {
+		data = &result->right;
+		start_atom = &data->atoms.head[cc->right.start];
+	} else
+		return DIFF_RC_OK;
+
+	diff_data_foreach_atom_backwards_from(start_atom, atom, data) {
+		for (i = 0; i < atom->len && i < sizeof(buf) - 1; i++) {
+			unsigned int ch;
+			rc = get_atom_byte(&ch, atom, i);
+			if (rc)
+				return rc;
+			if (ch == '\n')
+				break;
+			buf[i] = ch;
+		}
+		buf[i] = '\0';
+		if (is_function_prototype(buf)) {
+			*prototype = strdup(buf);
+			if (*prototype == NULL)
+				return ENOMEM;
+			return DIFF_RC_OK;
+		}
+	}
+
+	return DIFF_RC_OK;
+}
+
 struct diff_output_info *
 diff_output_info_alloc(void)
 {
blob - a0dba87608e0c39d9e91584b1864e08f921d39d3
blob + 5afb38442065c67a00db9ee4ff61c2348c491507
--- lib/diff_output_unidiff.c
+++ lib/diff_output_unidiff.c
@@ -200,11 +200,12 @@ output_unidiff_chunk(struct diff_output_info *outinfo,
 		     struct diff_output_unidiff_state *state,
 		     const struct diff_input_info *info,
 		     const struct diff_result *result,
-		     bool print_header,
+		     bool print_header, bool show_function_prototypes,
 		     const struct diff_chunk_context *cc)
 {
 	int rc, left_start, left_len, right_start, right_len;
 	off_t outoff = 0, *offp;
+	char *prototype = NULL;
 
 	if (diff_range_empty(&cc->left) && diff_range_empty(&cc->right))
 		return DIFF_RC_OK;
@@ -255,20 +256,36 @@ output_unidiff_chunk(struct diff_output_info *outinfo,
 		right_start = cc->right.start;
 	else
 		right_start = cc->right.start + 1;
+
+	if (show_function_prototypes) {
+		rc = diff_output_match_function_prototype(&prototype,
+		    result, cc);
+		if (rc)
+			return rc;
+	}
 
 	if (left_len == 1 && right_len == 1) {
-		rc = fprintf(dest, "@@ -%d +%d @@\n",
-			left_start, right_start);
+		rc = fprintf(dest, "@@ -%d +%d @@%s%s\n",
+			left_start, right_start,
+			prototype ? " " : "",
+			prototype ? : "");
 	} else if (left_len == 1 && right_len != 1) {
-		rc = fprintf(dest, "@@ -%d +%d,%d @@\n",
-			left_start, right_start, right_len);
+		rc = fprintf(dest, "@@ -%d +%d,%d @@%s%s\n",
+			left_start, right_start, right_len,
+			prototype ? " " : "",
+			prototype ? : "");
 	} else if (left_len != 1 && right_len == 1) {
-		rc = fprintf(dest, "@@ -%d,%d +%d @@\n",
-			left_start, left_len, right_start);
+		rc = fprintf(dest, "@@ -%d,%d +%d @@%s%s\n",
+			left_start, left_len, right_start,
+			prototype ? " " : "",
+			prototype ? : "");
 	} else {
-		rc = fprintf(dest, "@@ -%d,%d +%d,%d @@\n",
-			left_start, left_len, right_start, right_len);
+		rc = fprintf(dest, "@@ -%d,%d +%d,%d @@%s%s\n",
+			left_start, left_len, right_start, right_len,
+			prototype ? " " : "",
+			prototype ? : "");
 	}
+	free(prototype);
 	if (rc < 0)
 		return errno;
 	if (outinfo) {
@@ -352,6 +369,9 @@ diff_output_unidiff_chunk(struct diff_output_info **ou
 			  const struct diff_chunk_context *cc)
 {
 	struct diff_output_info *outinfo = NULL;
+	int flags = (result->left.root->diff_flags |
+	    result->right.root->diff_flags);
+	bool show_function_prototypes = (flags & DIFF_FLAG_SHOW_PROTOTYPES);
 
 	if (output_info) {
 		*output_info = diff_output_info_alloc();
@@ -361,7 +381,7 @@ diff_output_unidiff_chunk(struct diff_output_info **ou
 	}
 
 	return output_unidiff_chunk(outinfo, dest, state, info,
-	    result, false, cc);
+	    result, false, show_function_prototypes, cc);
 }
 
 int
@@ -373,6 +393,9 @@ 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 flags = (result->left.root->diff_flags |
+	    result->right.root->diff_flags);
+	bool show_function_prototypes = (flags & DIFF_FLAG_SHOW_PROTOTYPES);
 	int i;
 
 	if (!result)
@@ -461,7 +484,7 @@ diff_output_unidiff(struct diff_output_info **output_i
 		      " print left %d-%d right %d-%d\n",
 		      cc.left.start, cc.left.end, cc.right.start, cc.right.end);
 		output_unidiff_chunk(outinfo, dest, state, info, result,
-		    true, &cc);
+		    true, show_function_prototypes, &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);
@@ -469,7 +492,7 @@ diff_output_unidiff(struct diff_output_info **output_i
 
 	if (!diff_chunk_context_empty(&cc))
 		output_unidiff_chunk(outinfo, dest, state, info, result,
-		    true, &cc);
+		    true, show_function_prototypes, &cc);
 	diff_output_unidiff_state_free(state);
 	return DIFF_RC_OK;
 }