commit 14261ad5461e6c4b3ffc2f87131601ff79e2a0fc Author: Tim Waugh 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]);