Commit f3b2b5525998f769dba67674168f3ffb3cc495e5

Stefan Sperling 2020-12-10T16:58:11

sync files from diff.git b3fd1fa284e6207b923bd3c887364d9eb93fb340

diff --git a/lib/diff_internal.h b/lib/diff_internal.h
index 699cdbd..396f264 100644
--- a/lib/diff_internal.h
+++ b/lib/diff_internal.h
@@ -173,7 +173,9 @@ int diff_output_lines(struct diff_output_info *output_info, FILE *dest,
 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,
+#define DIFF_FUNCTION_CONTEXT_SIZE	55
+int diff_output_match_function_prototype(char *prototype, size_t prototype_size,
+					 int *last_prototype_idx,
 					 const struct diff_result *result,
 					 const struct diff_chunk_context *cc);
 
diff --git a/lib/diff_output.c b/lib/diff_output.c
index e286c62..daf8b8c 100644
--- a/lib/diff_output.c
+++ b/lib/diff_output.c
@@ -236,68 +236,67 @@ diff_output_trailing_newline_msg(struct diff_output_info *outinfo, FILE *dest,
 }
 
 static bool
-is_function_prototype(const char *buf)
+is_function_prototype(unsigned char ch)
 {
-	return isalpha(buf[0]) || buf[0] == '_' || buf[0] == '$';
+	return (isalpha(ch) || ch == '_' || ch == '$');
 }
 
-#define FUNCTION_CONTEXT_SIZE	55
 #define begins_with(s, pre) (strncmp(s, pre, sizeof(pre)-1) == 0)
 
 int
-diff_output_match_function_prototype(char **prototype,
-    const struct diff_result *result,
+diff_output_match_function_prototype(char *prototype, size_t prototype_size,
+    int *last_prototype_idx, 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];
+	unsigned char buf[DIFF_FUNCTION_CONTEXT_SIZE];
 	char *state = NULL;
-	int rc, i;
-
-	*prototype = NULL;
+	int rc, i, ch;
 
 	if (result->left->atoms.len > 0 && cc->left.start > 0) {
 		data = result->left;
 		start_atom = &data->atoms.head[cc->left.start - 1];
-	} else if (result->right->atoms.len > 0 && cc->right.start > 0) {
-		data = result->right;
-		start_atom = &data->atoms.head[cc->right.start - 1];
 	} 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;
+		int atom_idx = diff_atom_root_idx(data, atom);
+		if (atom_idx < *last_prototype_idx)
+			break;
+		rc = get_atom_byte(&ch, atom, 0);
+		if (rc)
+			return rc;
+		buf[0] = (unsigned char)ch;
+		if (!is_function_prototype(buf[0]))
+			continue;
+		for (i = 1; i < atom->len && i < sizeof(buf) - 1; i++) {
 			rc = get_atom_byte(&ch, atom, i);
 			if (rc)
 				return rc;
 			if (ch == '\n')
 				break;
-			buf[i] = ch;
+			buf[i] = (unsigned char)ch;
 		}
 		buf[i] = '\0';
-		if (is_function_prototype(buf)) {
-			if (begins_with(buf, "private:")) {
-				if (!state)
-					state = " (private)";
-			} else if (begins_with(buf, "protected:")) {
-				if (!state)
-					state = " (protected)";
-			} else if (begins_with(buf, "public:")) {
-				if (!state)
-					state = " (public)";
-			} else {
-				if (state)  /* don't care about truncation */
-					strlcat(buf, state, sizeof(buf));
-				*prototype = strdup(buf);
-				if (*prototype == NULL)
-					return ENOMEM;
-				return DIFF_RC_OK;
-			}
+		if (begins_with(buf, "private:")) {
+			if (!state)
+				state = " (private)";
+		} else if (begins_with(buf, "protected:")) {
+			if (!state)
+				state = " (protected)";
+		} else if (begins_with(buf, "public:")) {
+			if (!state)
+				state = " (public)";
+		} else {
+			if (state)  /* don't care about truncation */
+				strlcat(buf, state, sizeof(buf));
+			strlcpy(prototype, buf, prototype_size);
+			break;
 		}
 	}
 
+	*last_prototype_idx = diff_atom_root_idx(data, start_atom);
 	return DIFF_RC_OK;
 }
 
diff --git a/lib/diff_output_unidiff.c b/lib/diff_output_unidiff.c
index 0c30eea..5fc87f7 100644
--- a/lib/diff_output_unidiff.c
+++ b/lib/diff_output_unidiff.c
@@ -20,6 +20,7 @@
 #include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
 #include <assert.h>
 
 #include <arraylist.h>
@@ -189,6 +190,8 @@ diff_chunk_context_load_change(struct diff_chunk_context *cc,
 
 struct diff_output_unidiff_state {
 	bool header_printed;
+	char prototype[DIFF_FUNCTION_CONTEXT_SIZE];
+	int last_prototype_idx;
 };
 
 struct diff_output_unidiff_state *
@@ -206,6 +209,8 @@ void
 diff_output_unidiff_state_reset(struct diff_output_unidiff_state *state)
 {
 	state->header_printed = false;
+	memset(state->prototype, 0, sizeof(state->prototype));
+	state->last_prototype_idx = 0;
 }
 
 void
@@ -224,7 +229,6 @@ output_unidiff_chunk(struct diff_output_info *outinfo, FILE *dest,
 {
 	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;
@@ -279,7 +283,8 @@ output_unidiff_chunk(struct diff_output_info *outinfo, FILE *dest,
 		right_start = cc->right.start + 1;
 
 	if (show_function_prototypes) {
-		rc = diff_output_match_function_prototype(&prototype,
+		rc = diff_output_match_function_prototype(state->prototype,
+		    sizeof(state->prototype), &state->last_prototype_idx,
 		    result, cc);
 		if (rc)
 			return rc;
@@ -288,25 +293,24 @@ output_unidiff_chunk(struct diff_output_info *outinfo, FILE *dest,
 	if (left_len == 1 && right_len == 1) {
 		rc = fprintf(dest, "@@ -%d +%d @@%s%s\n",
 			left_start, right_start,
-			prototype ? " " : "",
-			prototype ? : "");
+			state->prototype[0] ? " " : "",
+			state->prototype[0] ? state->prototype : "");
 	} else if (left_len == 1 && right_len != 1) {
 		rc = fprintf(dest, "@@ -%d +%d,%d @@%s%s\n",
 			left_start, right_start, right_len,
-			prototype ? " " : "",
-			prototype ? : "");
+			state->prototype[0] ? " " : "",
+			state->prototype[0] ? state->prototype : "");
 	} else if (left_len != 1 && right_len == 1) {
 		rc = fprintf(dest, "@@ -%d,%d +%d @@%s%s\n",
 			left_start, left_len, right_start,
-			prototype ? " " : "",
-			prototype ? : "");
+			state->prototype[0] ? " " : "",
+			state->prototype[0] ? state->prototype : "");
 	} else {
 		rc = fprintf(dest, "@@ -%d,%d +%d,%d @@%s%s\n",
 			left_start, left_len, right_start, right_len,
-			prototype ? " " : "",
-			prototype ? : "");
+			state->prototype[0] ? " " : "",
+			state->prototype[0] ? state->prototype : "");
 	}
-	free(prototype);
 	if (rc < 0)
 		return errno;
 	if (outinfo) {