Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -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 \
Expand Down
12 changes: 9 additions & 3 deletions doc/patchutils.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1280,11 +1280,14 @@ filterdiff -i 'b/*/newname' git-patch-with-renames.patch]]></screen></para>
</varlistentry>
<varlistentry>
<term><option>-E</option>,
<option>--empty-files-as-absent</option>,
<option>--empty-files-as-removed</option></term>
<listitem>
<para>Treat empty files as absent for the purpose of
displaying file additions, modifications and
removals.</para>
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 (!).</para>
</listitem>
</varlistentry>
<varlistentry>
Expand Down Expand Up @@ -1646,12 +1649,15 @@ This is the same as gitdiff but uses git show instead of git diff.
</listitem>
</varlistentry>
<varlistentry>
<term><option>-E</option>,
<term>
<option>--empty-files-as-absent</option>,
<option>--empty-files-as-removed</option></term>
<listitem>
<para>Treat empty files as absent for the purpose of
displaying file additions, modifications and
removals.</para>
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 (<option>-E</option> means <option>--extended-regexp</option> for grepdiff).</para>
</listitem>
</varlistentry>
<varlistentry>
Expand Down
114 changes: 71 additions & 43 deletions src/filterdiff.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand All @@ -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) {
Expand All @@ -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;
Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -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);
}

Expand Down Expand Up @@ -756,24 +765,14 @@ 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;
}

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)
{
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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
Expand Down Expand 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);
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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"
Expand Down Expand Up @@ -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'},
Expand All @@ -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'},
Expand Down Expand Up @@ -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;
Expand Down
75 changes: 74 additions & 1 deletion tests/grepdiff-status/run-test
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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