diff --git a/src/filterdiff.c b/src/filterdiff.c index 4a00a7e2..33c94f76 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,6 +386,16 @@ 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) { @@ -394,7 +404,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; @@ -455,7 +465,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) { @@ -671,7 +681,7 @@ do_unified (FILE *f, char **header, unsigned int num_headers, if (!displayed_filename) { displayed_filename = 1; display_filename (start_linenum, - status, bestname, + *status, bestname, patchname); } @@ -746,6 +756,16 @@ 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; } @@ -753,7 +773,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) { @@ -1020,7 +1040,7 @@ do_context (FILE *f, char **header, unsigned int num_headers, if (!displayed_filename) { displayed_filename = 1; display_filename(start_linenum, - status, + *status, bestname, patchname); } @@ -1150,6 +1170,16 @@ 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; } @@ -1180,7 +1210,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 @@ -1375,19 +1405,13 @@ 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 (!orig_file_exists) - status = '+'; - else if (!new_file_exists) - status = '-'; - + if (match && show_status && mode == mode_list) display_filename (start_linenum, status, p, patchname); - } /* Clean up */ free (git_old_name); @@ -1476,19 +1500,13 @@ 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 (!orig_file_exists) - status = '+'; - else if (!new_file_exists) - status = '-'; - + if (match && show_status && mode == mode_list) display_filename (start_linenum, status, p, patchname); - } switch (result) { case EOF: @@ -1587,8 +1605,8 @@ const char * syntax_str = " prefix pathnames in old files with PREFIX\n" " --addnewprefix=PREFIX\n" " prefix pathnames in new files with PREFIX\n" -" -s, --status (lsdiff)\n" -" show file additions and removals (lsdiff)\n" +" -s, --status (lsdiff, grepdiff)\n" +" show file additions (+), removals (-), and modifications (!) (lsdiff, grepdiff)\n" " -v, --verbose\n" " verbose output -- use more than once for extra verbosity\n" " -E, --extended-regexp (grepdiff)\n" diff --git a/tests/grepdiff-status/run-test b/tests/grepdiff-status/run-test new file mode 100755 index 00000000..7b2bec4c --- /dev/null +++ b/tests/grepdiff-status/run-test @@ -0,0 +1,69 @@ +#!/bin/sh + +# Test grepdiff -s/--status option +# According to the documentation, -s should show: +# + for file additions +# - for file removals +# ! for file modifications + +. ${top_srcdir-.}/tests/common.sh + +cat << EOF > diff +--- /dev/null ++++ newfile +@@ -0,0 +1 @@ ++content +--- oldfile ++++ /dev/null +@@ -1 +0,0 @@ +-content +--- modified ++++ modified +@@ -1 +1 @@ +-old ++new +--- another-modified ++++ another-modified +@@ -1,2 +1,2 @@ + context +-old content ++new content +EOF + +# Test additions and deletions (files with 'content' pattern) +${GREPDIFF} -s 'content' diff 2>errors >output || exit 1 +[ -s errors ] && exit 1 + +cat << EOF | cmp - output || exit 1 ++ newfile +- oldfile +! another-modified +EOF + +# Test modification only (file with 'new' pattern) +${GREPDIFF} -s 'new' diff 2>errors >output2 || exit 1 +[ -s errors ] && exit 1 + +cat << EOF | cmp - output2 || exit 1 +! modified +! another-modified +EOF + +# Test with --empty-files-as-absent +# File with only additions should be treated as new file +cat << EOF > diff3 +--- emptyfile ++++ emptyfile +@@ -0,0 +1 @@ ++content +@@ -60 +60 @@ +-old ++new +EOF + +${GREPDIFF} -s --empty-files-as-absent 'content' diff3 2>errors >output3 || exit 1 +[ -s errors ] && exit 1 + +cat << EOF | cmp - output3 || exit 1 ++ emptyfile +EOF