fix: reject multiple patterns when -P/--perl-regexp is used

GNU grep's PCRE backend supports only a single pattern. Supplying
multiple patterns via repeated -e flags, or a pattern string that
contains a literal newline, must exit 2 with the message:

    the -P option only supports a single pattern

Add the validation immediately after patterns are collected, before
regex-mode selection. Add a test covering:
  - two separate -e flags with -P
  - a newline-embedded pattern string with -P
  - single -e with -P still works normally

Closes #34
This commit is contained in:
Kanishk Sachan
2026-06-05 01:25:22 +01:00
parent f4798cb6d0
commit e3d80f59e2
2 changed files with 36 additions and 0 deletions
+8
View File
@@ -255,6 +255,14 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
));
}
// GNU grep's PCRE backend (-P) supports only a single pattern.
if perl_regexp && patterns.len() > 1 {
return Err(USimpleError::new(
2,
"the -P option only supports a single pattern".to_string(),
));
}
// Decoded options into enums
let regex_mode = if fixed_strings {
RegexMode::Fixed
+28
View File
@@ -170,6 +170,34 @@ fn pcre_features() {
.stdout_only("42\n7\n");
}
#[test]
fn perl_regexp_rejects_multiple_patterns() {
// GNU grep's PCRE backend (-P) only supports a single pattern.
// Multiple -e patterns must produce exit 2 and the canonical error message.
// See: https://github.com/uutils/grep/issues/34
// Two separate -e flags.
let (_s, mut c) = ucmd();
c.args(&["-P", "-e", "foo", "-e", "bar"])
.pipe_in("foo\nbar\n")
.fails_with_code(2)
.stderr_contains("the -P option only supports a single pattern");
// A newline inside the pattern string is split into multiple patterns.
let (_s, mut c) = ucmd();
c.args(&["-P", "-e", "foo\nbar"])
.pipe_in("foo\nbar\n")
.fails_with_code(2)
.stderr_contains("the -P option only supports a single pattern");
// A single pattern with -P must still work normally.
let (_s, mut c) = ucmd();
c.args(&["-P", "-e", r"\d+"])
.pipe_in("abc\n42\n")
.succeeds()
.stdout_only("42\n");
}
#[test]
fn posix_character_classes() {
let (_s, mut c) = ucmd();