Blob Blame History Raw
commit 14261ad5461e6c4b3ffc2f87131601ff79e2a0fc
Author: Tim Waugh <twaugh@redhat.com>
Date:   Tue Apr 14 17:33:49 2015 +0100

    Handle git extended headers.
    
    The fullheader1 test case should now pass.

diff --git a/src/filterdiff.c b/src/filterdiff.c
index d6f121e..2870746 100644
--- a/src/filterdiff.c
+++ b/src/filterdiff.c
@@ -279,7 +279,8 @@ hunk_matches (unsigned long orig_offset, unsigned long orig_count,
 }
 
 static int
-do_unified (FILE *f, char *header[2], int match, char **line,
+do_unified (FILE *f, char **header, unsigned int num_headers,
+            int match, char **line,
 	    size_t *linelen, unsigned long *linenum,
 	    unsigned long start_linenum, char status,
 	    const char *bestname, const char *patchname,
@@ -390,10 +391,13 @@ do_unified (FILE *f, char *header[2], int match, char **line,
 				if (!header_displayed &&
 				    mode != mode_grep) {
 					// Display the header.
+                                        unsigned int i;
+                                        for (i = 0; i < num_headers - 2; i++)
+                                                output_header_line (header[i]);
 					if (number_lines != After)
-						output_header_line (header[0]);
+						output_header_line (header[num_headers - 2]);
 					if (number_lines != Before)
-						output_header_line (header[1]);
+						output_header_line (header[num_headers - 1]);
 					header_displayed = 1;
 				}
 				switch (number_lines) {
@@ -476,16 +480,16 @@ do_unified (FILE *f, char *header[2], int match, char **line,
 				}
 			} else {
 				if (match_tmpf) {
-					if (!header_displayed &&
-					    number_lines != After)
-						output_header_line (header[0]);
-
-					if (!header_displayed &&
-					    number_lines != Before)
-						output_header_line (header[1]);
-
-					if (!header_displayed)
+                                        if (!header_displayed) {
+                                                unsigned int i;
+                                                for (i = 0; i < num_headers - 2; i++)
+                                                        output_header_line (header[i]);
+                                                if (number_lines != After)
+                                                        output_header_line (header[num_headers - 2]);
+                                                if (number_lines != Before)
+                                                        output_header_line (header[num_headers - 1]);
 						header_displayed = 1;
+                                        }
 
 					rewind (match_tmpf);
 					while (!feof (match_tmpf)) {
@@ -533,7 +537,8 @@ do_unified (FILE *f, char *header[2], int match, char **line,
 }
 
 static int
-do_context (FILE *f, char *header[2], int match, char **line,
+do_context (FILE *f, char **header, unsigned int num_headers,
+            int match, char **line,
 	    size_t *linelen, unsigned long *linenum,
 	    unsigned long start_linenum, char status,
 	    const char *bestname, const char *patchname,
@@ -687,10 +692,13 @@ do_context (FILE *f, char *header[2], int match, char **line,
 
 			// Display the line counts.
 			if (!header_displayed && mode == mode_filter) {
+                                unsigned int i;
+                                for (i = 0; i < num_headers - 2; i++)
+                                        output_header_line (header[i]);
 				if (number_lines != After)
-					output_header_line (header[0]);
+					output_header_line (header[num_headers - 2]);
 				if (number_lines != Before)
-					output_header_line (header[1]);
+					output_header_line (header[num_headers - 1]);
 				header_displayed = 1;
 			}
 
@@ -787,10 +795,13 @@ do_context (FILE *f, char *header[2], int match, char **line,
 					}
 				} else {
 					if (!header_displayed) {
+                                                unsigned int i;
+                                                for (i = 0; i < num_headers - 2; i++)
+                                                        output_header_line (header[i]);
 						if (number_lines != After)
-							output_header_line (header[0]);
+							output_header_line (header[num_headers - 2]);
 						if (number_lines != Before)
-							output_header_line (header[1]);
+							output_header_line (header[num_headers - 1]);
 						header_displayed = 1;
 					}
 
@@ -899,11 +910,13 @@ out:
 	return ret;
 }
 
+#define MAX_HEADERS 5
 static int filterdiff (FILE *f, const char *patchname)
 {
 	static unsigned long linenum = 1;
 	char *names[2];
-	char *header[2] = { NULL, NULL };
+	char *header[MAX_HEADERS] = { NULL, NULL };
+        unsigned int num_headers = 0;
 	char *line = NULL;
 	size_t linelen = 0;
 	char *p;
@@ -918,18 +931,22 @@ static int filterdiff (FILE *f, const char *patchname)
 		char status = '!';
 		unsigned long start_linenum;
 		int orig_file_exists, new_file_exists;
-		int is_context = 0;
+		int is_context = -1;
 		int result;
-		int (*do_diff) (FILE *, char *[2], int, char **, size_t *,
+		int (*do_diff) (FILE *, char **, unsigned int,
+                                int, char **, size_t *,
 				unsigned long *, unsigned long,
 				char, const char *, const char *,
 				int *, int *);
 
 		orig_file_exists = 0; // shut gcc up
 
-		// Search for start of patch ("--- " for unified diff,
-		// "*** " for context).
+		// Search for start of patch ("diff ", or "--- " for
+		// unified diff, "*** " for context).
 		for (;;) {
+                        if (!strncmp (line, "diff ", 5))
+                                break;
+
 			if (!strncmp (line, "--- ", 4)) {
 				is_context = 0;
 				break;
@@ -953,6 +970,70 @@ static int filterdiff (FILE *f, const char *patchname)
 
 		start_linenum = linenum;
 		header[0] = xstrdup (line);
+                num_headers = 1;
+
+                if (is_context == -1) {
+                        int valid_extended = 1;
+                        for (;;) {
+                                if (getline (&line, &linelen, f) == -1)
+                                        goto eof;
+                                linenum++;
+
+                                if (!strncmp (line, "diff ", 5)) {
+                                        header[num_headers++] = xstrdup (line);
+                                        break;
+                                }
+
+                                if (!strncmp (line, "--- ", 4))
+                                        is_context = 0;
+                                else if (!strncmp (line, "*** ", 4))
+                                        is_context = 1;
+                                else if (strncmp (line, "old mode ", 9) &&
+                                    strncmp (line, "new mode ", 9) &&
+                                    strncmp (line, "deleted file mode ", 18) &&
+                                    strncmp (line, "new file mode ", 15) &&
+                                    strncmp (line, "copy from ", 10) &&
+                                    strncmp (line, "copy to ", 8) &&
+                                    strncmp (line, "rename from ", 12) &&
+                                    strncmp (line, "rename to ", 10) &&
+                                    strncmp (line, "similarity index ", 17) &&
+                                    strncmp (line, "dissimilarity index ", 20) &&
+                                    strncmp (line, "index ", 6))
+                                        valid_extended = 0;
+
+                                if (!valid_extended)
+                                        break;
+
+                                /* Drop excess header lines */
+                                if (num_headers < MAX_HEADERS - 2)
+                                        header[num_headers++] = xstrdup (line);
+
+                                if (is_context != -1)
+                                        break;
+                        }
+
+                        if (!valid_extended)
+                                goto flush_continue;
+                }
+
+                if (is_context == -1) {
+                        /* We don't yet do anything with diffs with
+                         * zero hunks. */
+                        unsigned int i = 0;
+                flush_continue:
+                        if (mode == mode_filter && (pat_exclude || verbose)
+                            && !clean_comments) {
+                                for (i = 0; i < num_headers; i++)
+                                        fputs (header[i], stdout);
+                        }
+                        for (i = 0; i < num_headers; i++) {
+                                free (header[i]);
+                                header[i] = NULL;
+                        }
+                        num_headers = 0;
+                        continue;
+                }
+
 		names[0] = filename_from_header (line + 4);
 		if (mode != mode_filter && show_status)
 			orig_file_exists = file_exists (names[0], line + 4 +
@@ -972,17 +1053,12 @@ static int filterdiff (FILE *f, const char *patchname)
 		if (strncmp (line, is_context ? "--- " : "+++ ", 4)) {
 			/* Show non-diff lines if excluding, or if
 			 * in verbose mode, and if --clean isn't specified. */
-			if (mode == mode_filter && (pat_exclude || verbose)
-				&& !clean_comments)
-				fputs (header[0], stdout);
 			free (names[0]);
-			free (header[0]);
-			header[0] = NULL;
-			continue;
+                        goto flush_continue;
 		}
 
 		filecount++;
-		header[1] = xstrdup (line);
+		header[num_headers++] = xstrdup (line);
 		names[1] = filename_from_header (line + 4);
 
 		if (mode != mode_filter && show_status)
@@ -1007,7 +1083,8 @@ static int filterdiff (FILE *f, const char *patchname)
 		else
 			do_diff = do_unified;
 
-		result = do_diff (f, header, match, &line,
+		result = do_diff (f, header, num_headers,
+                                  match, &line,
 				  &linelen, &linenum,
 				  start_linenum, status, p, patchname,
 				  &orig_file_exists, &new_file_exists);
@@ -1033,15 +1110,17 @@ static int filterdiff (FILE *f, const char *patchname)
 		}
 
 	next_diff:
-		for (i = 0; i < 2; i++) {
+		for (i = 0; i < 2; i++)
 			free (names[i]);
+                for (i = 0; i < num_headers; i++) {
 			free (header[i]);
 			header[i] = NULL;
 		}
+                num_headers = 0;
 	}
 
  eof:
-	for (i = 0; i < 2; i++)
+	for (i = 0; i < num_headers; i++)
 		if (header[i])
 			free (header[i]);