diff --git a/Makefile.am b/Makefile.am index 2294ed3..79b41f1 100644 --- a/Makefile.am +++ b/Makefile.am @@ -225,6 +225,7 @@ TESTS = tests/newline1/run-test \ tests/grepdiff8/run-test \ tests/grepdiff9/run-test \ tests/grepdiff-original-line-numbers/run-test \ + tests/grepdiff-status/run-test \ tests/number1/run-test \ tests/number2/run-test \ tests/number3/run-test \ diff --git a/doc/patchutils.xml b/doc/patchutils.xml index b561852..b862571 100644 --- a/doc/patchutils.xml +++ b/doc/patchutils.xml @@ -1280,11 +1280,14 @@ filterdiff -i 'b/*/newname' git-patch-with-renames.patch]]> , + , Treat empty files as absent for the purpose of displaying file additions, modifications and - removals. + removals. For example, a file with an empty old version + and additions in the new version will be treated as a + file addition (+) rather than a modification (!). @@ -1646,12 +1649,15 @@ This is the same as gitdiff but uses git show instead of git diff. - , + + , Treat empty files as absent for the purpose of displaying file additions, modifications and - removals. + removals. For example, a file with an empty old version + and additions in the new version will be treated as a + file addition (+) rather than a modification (!). Note: For grepdiff, only the long form is available ( means for grepdiff). diff --git a/src/filterdiff.c b/src/filterdiff.c index 33c94f7..9e70c19 100644 --- a/src/filterdiff.c +++ b/src/filterdiff.c @@ -359,7 +359,7 @@ static int do_git_diff_no_hunks (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, + char status, const char *bestname, const char *patchname, int *orig_file_exists, int *new_file_exists, enum git_diff_type git_type) { @@ -386,16 +386,6 @@ do_git_diff_no_hunks (FILE *f, char **header, unsigned int num_headers, break; } - /* Update status based on file existence (do this early so returns below have correct status) */ - if (status != NULL && mode != mode_filter && show_status && - orig_file_exists != NULL && new_file_exists != NULL) { - if (!*orig_file_exists) - *status = '+'; - else if (!*new_file_exists) - *status = '-'; - /* else: keep existing '!' value for modifications */ - } - /* If this diff matches the filter, display it */ if (match) { if (mode == mode_filter) { @@ -404,7 +394,7 @@ do_git_diff_no_hunks (FILE *f, char **header, unsigned int num_headers, fputs (header[i], stdout); } else if (mode == mode_list && !displayed_filename) { if (!show_status) { - display_filename (start_linenum, *status, + display_filename (start_linenum, status, bestname, patchname); } displayed_filename = 1; @@ -465,7 +455,7 @@ static int 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, + unsigned long start_linenum, char status, const char *bestname, const char *patchname, int *orig_file_exists, int *new_file_exists) { @@ -679,9 +669,28 @@ do_unified (FILE *f, char **header, unsigned int num_headers, !regexecs (regex, num_regex, *line + 1, 0, NULL, 0)) { if (output_matching == output_none) { if (!displayed_filename) { + char display_status = status; + /* Update status based on file existence for grepdiff -s */ + if (show_status) { + int orig_absent = orig_file_exists && !*orig_file_exists; + int new_absent = new_file_exists && !*new_file_exists; + + /* Check for empty files if --empty-files-as-absent is set */ + if (empty_files_as_absent) { + if (orig_file_exists && *orig_file_exists && orig_is_empty) + orig_absent = 1; + if (new_file_exists && *new_file_exists && new_is_empty) + new_absent = 1; + } + + if (orig_absent) + display_status = '+'; + else if (new_absent) + display_status = '-'; + } displayed_filename = 1; display_filename (start_linenum, - *status, bestname, + display_status, bestname, patchname); } @@ -756,16 +765,6 @@ do_unified (FILE *f, char **header, unsigned int num_headers, *new_file_exists = 0; } - /* Update status based on final file existence after empty file processing */ - if (status != NULL && mode != mode_filter && show_status && - orig_file_exists != NULL && new_file_exists != NULL) { - if (!*orig_file_exists) - *status = '+'; - else if (!*new_file_exists) - *status = '-'; - /* else: keep existing '!' value for modifications */ - } - return ret; } @@ -773,7 +772,7 @@ static int 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, + unsigned long start_linenum, char status, const char *bestname, const char *patchname, int *orig_file_exists, int *new_file_exists) { @@ -1038,9 +1037,28 @@ do_context (FILE *f, char **header, unsigned int num_headers, 0, NULL, 0)) { if (output_matching == output_none) { if (!displayed_filename) { + char display_status = status; + /* Update status based on file existence for grepdiff -s */ + if (show_status) { + int orig_absent = orig_file_exists && !*orig_file_exists; + int new_absent = new_file_exists && !*new_file_exists; + + /* Check for empty files if --empty-files-as-absent is set */ + if (empty_files_as_absent) { + if (orig_file_exists && *orig_file_exists && orig_is_empty) + orig_absent = 1; + if (new_file_exists && *new_file_exists && new_is_empty) + new_absent = 1; + } + + if (orig_absent) + display_status = '+'; + else if (new_absent) + display_status = '-'; + } displayed_filename = 1; display_filename(start_linenum, - *status, + display_status, bestname, patchname); } @@ -1170,16 +1188,6 @@ do_context (FILE *f, char **header, unsigned int num_headers, *new_file_exists = 0; } - /* Update status based on final file existence after empty file processing */ - if (status != NULL && mode != mode_filter && show_status && - orig_file_exists != NULL && new_file_exists != NULL) { - if (!*orig_file_exists) - *status = '+'; - else if (!*new_file_exists) - *status = '-'; - /* else: keep existing '!' value for modifications */ - } - return ret; } @@ -1210,7 +1218,7 @@ static int filterdiff (FILE *f, const char *patchname) int (*do_diff) (FILE *, char **, unsigned int, int, char **, size_t *, unsigned long *, unsigned long, - char *, const char *, const char *, + char, const char *, const char *, int *, int *); orig_file_exists = 0; // shut gcc up @@ -1405,13 +1413,19 @@ static int filterdiff (FILE *f, const char *patchname) /* Process the git diff (it will handle filename display) */ result = do_git_diff_no_hunks (f, header, num_headers, match, &line, &linelen, &linenum, - start_linenum, &status, p, patchname, + start_linenum, status, p, patchname, &orig_file_exists, &new_file_exists, git_type); /* Print filename with status if in list mode and matches */ - if (match && show_status && mode == mode_list) + if (match && show_status && mode == mode_list) { + if (!orig_file_exists) + status = '+'; + else if (!new_file_exists) + status = '-'; + display_filename (start_linenum, status, p, patchname); + } /* Clean up */ free (git_old_name); @@ -1500,13 +1514,19 @@ static int filterdiff (FILE *f, const char *patchname) result = do_diff (f, header, num_headers, match, &line, &linelen, &linenum, - start_linenum, &status, p, patchname, + start_linenum, status, p, patchname, &orig_file_exists, &new_file_exists); // print if it matches. - if (match && show_status && mode == mode_list) + if (match && show_status && mode == mode_list) { + if (!orig_file_exists) + status = '+'; + else if (!new_file_exists) + status = '-'; + display_filename (start_linenum, status, p, patchname); + } switch (result) { case EOF: @@ -1617,6 +1637,8 @@ const char * syntax_str = #endif " -E, --empty-files-as-absent (lsdiff)\n" " treat empty files as absent (lsdiff)\n" +" --empty-files-as-absent (grepdiff)\n" +" treat empty files as absent (grepdiff)\n" " -f FILE, --file=FILE (grepdiff)\n" " read regular expressions from FILE (grepdiff)\n" " --filter run as 'filterdiff' (grepdiff, patchview, lsdiff)\n" @@ -1840,7 +1862,7 @@ int main (int argc, char *argv[]) {"remove-timestamps", 0, 0, 1000 + 'r'}, {"with-filename", 0, 0, 'H'}, {"no-filename", 0, 0, 'h'}, - {"empty-files-as-absent", 0, 0, 'E'}, + {"empty-files-as-absent", 0, 0, 1000 + 'E'}, {"number-files", 0, 0, 'N'}, {"clean", 0, 0, 1000 + 'c'}, {"strip-match", 1, 0, 'p'}, @@ -1853,7 +1875,7 @@ int main (int argc, char *argv[]) {"strip-match", 1, 0, 'p'}, {"status", 0, 0, 's'}, {"extended-regexp", 0, 0, 'E'}, - {"empty-files-as-removed", 0, 0, 'E'}, + {"empty-files-as-removed", 0, 0, 1000 + 'E'}, {"file", 1, 0, 'f'}, {"in-place", 0, 0, 1000 + 'w'}, {"git-prefixes", 1, 0, 1000 + 'G'}, @@ -1883,6 +1905,12 @@ int main (int argc, char *argv[]) empty_files_as_absent = 1; else syntax (1); break; + case 1000 + 'E': + /* Long form --empty-files-as-absent or --empty-files-as-removed */ + if (mode == mode_grep || mode == mode_list) + empty_files_as_absent = 1; + else syntax (1); + break; case 'f': if (mode == mode_grep) { regex_file_specified = 1; diff --git a/tests/grepdiff-status/run-test b/tests/grepdiff-status/run-test index 7b2bec4..380a60a 100755 --- a/tests/grepdiff-status/run-test +++ b/tests/grepdiff-status/run-test @@ -49,7 +49,7 @@ cat << EOF | cmp - output2 || exit 1 ! another-modified EOF -# Test with --empty-files-as-absent +# Test with --empty-files-as-absent for file addition # File with only additions should be treated as new file cat << EOF > diff3 --- emptyfile @@ -67,3 +67,76 @@ ${GREPDIFF} -s --empty-files-as-absent 'content' diff3 2>errors >output3 || exit cat << EOF | cmp - output3 || exit 1 + emptyfile EOF + +# Test with --empty-files-as-absent for file deletion +# File with only deletions should be treated as deleted +cat << EOF > diff4 +--- deletedfile ++++ deletedfile +@@ -1 +0,0 @@ +-content +@@ -60 +60 @@ +-old ++new +EOF + +${GREPDIFF} -s --empty-files-as-absent 'content' diff4 2>errors >output4 || exit 1 +[ -s errors ] && exit 1 + +cat << EOF | cmp - output4 || exit 1 +- deletedfile +EOF + +# Test with context diff format +cat << EOF > diff5 +*** /dev/null +--- newfile-ctx +*************** +*** 0 **** +--- 1 ---- ++ content +*** oldfile-ctx +--- /dev/null +*************** +*** 1 **** +- content +--- 0 ---- +*** modified-ctx +--- modified-ctx +*************** +*** 1 **** +! old content +--- 1 ---- +! new content +EOF + +${GREPDIFF} -s 'content' diff5 2>errors >output5 || exit 1 +[ -s errors ] && exit 1 + +cat << EOF | cmp - output5 || exit 1 ++ newfile-ctx +- oldfile-ctx +! modified-ctx +EOF + +# Test context diff with --empty-files-as-absent +cat << EOF > diff6 +*** emptyfile-ctx +--- emptyfile-ctx +*************** +*** 0 **** +--- 1 ---- ++ content +*************** +*** 60 **** +! old +--- 60 ---- +! new +EOF + +${GREPDIFF} -s --empty-files-as-absent 'content' diff6 2>errors >output6 || exit 1 +[ -s errors ] && exit 1 + +cat << EOF | cmp - output6 || exit 1 ++ emptyfile-ctx +EOF