Skip to content

Commit a2e9bfb

Browse files
committed
New lsdiff: add file range exclusion and a test for it
Assisted-by: Cursor
1 parent 6b530da commit a2e9bfb

3 files changed

Lines changed: 164 additions & 35 deletions

File tree

Makefile.am

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,7 @@ TESTS = tests/newline1/run-test \
213213
tests/lsdiff13/run-test \
214214
tests/lsdiff14/run-test \
215215
tests/lsdiff15/run-test \
216+
tests/lsdiff-range-exclude/run-test \
216217
tests/patchview1/run-test \
217218
tests/patchview2/run-test \
218219
tests/fuzz1/run-test \

src/lsdiff.c

Lines changed: 53 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,6 @@
1717
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
1818
*
1919
* This is a scanner-based implementation of lsdiff using the unified patch scanner API.
20-
*
21-
* TODO: REMAINING IMPROVEMENTS
22-
* ============================
23-
* RANGE PARSING IMPROVEMENTS:
24-
* Full range syntax for -F/--files option: "1,3-5,8", "3-", "-", "x1,3" (exclusion)
25-
* Currently only supports single numbers
26-
*
27-
* See filterdiff.c for reference implementation of full range parsing.
2820
*/
2921

3022
#ifdef HAVE_CONFIG_H
@@ -74,6 +66,7 @@ static char *add_new_prefix = NULL; /* --addnewprefix */
7466
static struct patlist *pat_include = NULL; /* -i, --include */
7567
static struct patlist *pat_exclude = NULL; /* -x, --exclude */
7668
static struct range *files = NULL; /* -F, --files */
69+
static int files_exclude = 0; /* -F with x prefix */
7770

7871
/* File counter for -N option */
7972
static int file_number = 0;
@@ -431,17 +424,20 @@ static int should_display_file(const char *filename)
431424
struct range *r;
432425
int file_matches = 0;
433426

434-
/* TODO: Handle files_exclude flag and range exclusion (x prefix) */
435-
427+
/* Check if file number matches any range (-1UL is wildcard) */
436428
for (r = files; r; r = r->next) {
437-
if (file_number >= r->start && file_number <= r->end) {
429+
if ((r->start == -1UL || r->start <= file_number) &&
430+
(r->end == -1UL || file_number <= r->end)) {
438431
file_matches = 1;
439432
break;
440433
}
441434
}
442435

443-
if (!file_matches)
444-
return 0;
436+
/* Handle exclusion logic */
437+
if (files && !file_matches && !files_exclude)
438+
return 0; /* File doesn't match and we're including */
439+
if (files && file_matches && files_exclude)
440+
return 0; /* File matches and we're excluding */
445441
}
446442

447443
return 1;
@@ -721,6 +717,12 @@ int main(int argc, char *argv[])
721717
patlist_add_file(&pat_exclude, optarg);
722718
break;
723719
case 'F':
720+
if (files)
721+
syntax(1);
722+
if (*optarg == 'x') {
723+
files_exclude = 1;
724+
optarg = optarg + 1;
725+
}
724726
parse_range(&files, optarg);
725727
break;
726728
case 'v':
@@ -821,35 +823,51 @@ int main(int argc, char *argv[])
821823
* Used with -F option to select specific files from a patch by their
822824
* position (file number), which can then be used with filterdiff's
823825
* --files option for further processing.
824-
*
825-
* This is a simplified implementation that only supports single numbers.
826-
* The full implementation in filterdiff.c supports all range formats above.
827-
*
828-
* TODO: Implement full range parsing functionality:
829-
* - Support ranges: "3-5", "3-", "-"
830-
* - Support comma-separated lists: "1,3-5,8"
831-
* - Support exclusion ranges with 'x' prefix: "x1,3"
832-
* - Add proper error handling for invalid ranges
833-
*
834-
* Current implementation only supports single numbers like "3".
835826
*/
836827
static void parse_range(struct range **r, const char *rstr)
837828
{
838829
unsigned long n;
839830
char *end;
840-
struct range *new_range;
841831

842-
n = strtoul(rstr, &end, 0);
843-
if (rstr == end)
844-
return; /* Invalid number */
832+
if (*rstr == '-')
833+
n = -1UL;
834+
else {
835+
n = strtoul(rstr, &end, 0);
836+
if (rstr == end) {
837+
if (*end)
838+
error(EXIT_FAILURE, 0,
839+
"not understood: '%s'", end);
840+
else
841+
error(EXIT_FAILURE, 0,
842+
"missing number in range list");
843+
844+
*r = NULL;
845+
return;
846+
}
845847

846-
new_range = malloc(sizeof(struct range));
847-
if (!new_range)
848-
return;
848+
rstr = end;
849+
}
850+
851+
*r = xmalloc(sizeof **r);
852+
(*r)->start = (*r)->end = n;
853+
(*r)->next = NULL;
854+
if (*rstr == '-') {
855+
rstr++;
856+
n = strtoul(rstr, &end, 0);
857+
if (rstr == end)
858+
n = -1UL;
859+
860+
(*r)->end = n;
861+
rstr = end;
862+
863+
if ((*r)->start != -1UL && (*r)->start > (*r)->end)
864+
error(EXIT_FAILURE, 0, "invalid range: %lu-%lu",
865+
(*r)->start, (*r)->end);
866+
}
849867

850-
new_range->start = n;
851-
new_range->end = n;
852-
new_range->next = *r;
853-
*r = new_range;
868+
if (*rstr == ',')
869+
parse_range(&(*r)->next, rstr + 1);
870+
else if (*rstr != '\0')
871+
error(EXIT_FAILURE, 0, "not understood: '%s'", rstr);
854872
}
855873

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
#!/bin/sh
2+
3+
# This is a lsdiff(1) testcase for range exclusion functionality (-F x prefix).
4+
5+
. ${top_srcdir-.}/tests/common.sh
6+
7+
# Create a patch with 5 files to test various range exclusion patterns
8+
cat << EOF > multi-file.patch
9+
--- file1.txt
10+
+++ file1.txt
11+
@@ -1 +1 @@
12+
-old1
13+
+new1
14+
--- file2.txt
15+
+++ file2.txt
16+
@@ -1 +1 @@
17+
-old2
18+
+new2
19+
--- file3.txt
20+
+++ file3.txt
21+
@@ -1 +1 @@
22+
-old3
23+
+new3
24+
--- file4.txt
25+
+++ file4.txt
26+
@@ -1 +1 @@
27+
-old4
28+
+new4
29+
--- file5.txt
30+
+++ file5.txt
31+
@@ -1 +1 @@
32+
-old5
33+
+new5
34+
EOF
35+
36+
# Test 1: Exclude single file (x2) - should show files 1, 3, 4, 5
37+
echo "Testing single file exclusion (x2)..."
38+
${LSDIFF} -F x2 multi-file.patch 2>errors1 >result1 || exit 1
39+
[ -s errors1 ] && { echo "Unexpected errors in test 1:"; cat errors1; exit 1; }
40+
41+
cat << EOF | cmp - result1 || { echo "Test 1 failed"; exit 1; }
42+
file1.txt
43+
file3.txt
44+
file4.txt
45+
file5.txt
46+
EOF
47+
48+
# Test 2: Exclude comma-separated list (x1,3,5) - should show files 2, 4
49+
echo "Testing comma-separated exclusion (x1,3,5)..."
50+
${LSDIFF} -F x1,3,5 multi-file.patch 2>errors2 >result2 || exit 1
51+
[ -s errors2 ] && { echo "Unexpected errors in test 2:"; cat errors2; exit 1; }
52+
53+
cat << EOF | cmp - result2 || { echo "Test 2 failed"; exit 1; }
54+
file2.txt
55+
file4.txt
56+
EOF
57+
58+
# Test 3: Exclude range (x2-4) - should show files 1, 5
59+
echo "Testing range exclusion (x2-4)..."
60+
${LSDIFF} -F x2-4 multi-file.patch 2>errors3 >result3 || exit 1
61+
[ -s errors3 ] && { echo "Unexpected errors in test 3:"; cat errors3; exit 1; }
62+
63+
cat << EOF | cmp - result3 || { echo "Test 3 failed"; exit 1; }
64+
file1.txt
65+
file5.txt
66+
EOF
67+
68+
# Test 4: Exclude open-ended range (x3-) - should show files 1, 2
69+
echo "Testing open-ended range exclusion (x3-)..."
70+
${LSDIFF} -F x3- multi-file.patch 2>errors4 >result4 || exit 1
71+
[ -s errors4 ] && { echo "Unexpected errors in test 4:"; cat errors4; exit 1; }
72+
73+
cat << EOF | cmp - result4 || { echo "Test 4 failed"; exit 1; }
74+
file1.txt
75+
file2.txt
76+
EOF
77+
78+
# Test 5: Mixed exclusion (x1,4-5) - should show files 2, 3
79+
echo "Testing mixed exclusion (x1,4-5)..."
80+
${LSDIFF} -F x1,4-5 multi-file.patch 2>errors5 >result5 || exit 1
81+
[ -s errors5 ] && { echo "Unexpected errors in test 5:"; cat errors5; exit 1; }
82+
83+
cat << EOF | cmp - result5 || { echo "Test 5 failed"; exit 1; }
84+
file2.txt
85+
file3.txt
86+
EOF
87+
88+
# Test 6: Compare with positive range selection to ensure exclusion works correctly
89+
# First test positive selection (2,4) - should show files 2, 4
90+
echo "Testing positive range selection for comparison (2,4)..."
91+
${LSDIFF} -F 2,4 multi-file.patch 2>errors6 >result6 || exit 1
92+
[ -s errors6 ] && { echo "Unexpected errors in test 6:"; cat errors6; exit 1; }
93+
94+
cat << EOF | cmp - result6 || { echo "Test 6 failed"; exit 1; }
95+
file2.txt
96+
file4.txt
97+
EOF
98+
99+
# Test 7: Verify that exclusion of 2,4 gives the complement of positive selection
100+
echo "Testing exclusion complement (x2,4)..."
101+
${LSDIFF} -F x2,4 multi-file.patch 2>errors7 >result7 || exit 1
102+
[ -s errors7 ] && { echo "Unexpected errors in test 7:"; cat errors7; exit 1; }
103+
104+
cat << EOF | cmp - result7 || { echo "Test 7 failed"; exit 1; }
105+
file1.txt
106+
file3.txt
107+
file5.txt
108+
EOF
109+
110+
echo "All range exclusion tests passed!"

0 commit comments

Comments
 (0)