diff --git a/src/find/matchers/printf.rs b/src/find/matchers/printf.rs index 038ec7fb..906e1594 100644 --- a/src/find/matchers/printf.rs +++ b/src/find/matchers/printf.rs @@ -149,7 +149,7 @@ impl FormatStringParser<'_> { fn advance_one(&mut self) -> Result> { let c = self.front()?; - self.string = &self.string[1..]; + self.string = &self.string[c.len_utf8()..]; Ok(c) } @@ -719,6 +719,16 @@ mod tests { ); } + #[test] + fn test_parse_multibyte_char_after_directive() { + assert_eq!( + FormatString::parse("%€").unwrap().components, + vec![FormatComponent::Literal("€".to_owned())] + ); + assert!(FormatString::parse("\\€").is_err()); + assert!(FormatString::parse("%A€").is_err()); + } + #[test] fn test_parse_formatting() { fn unaligned_directive(directive: FormatDirective) -> FormatComponent { diff --git a/tests/test_find.rs b/tests/test_find.rs index cfee583f..997c0bfe 100644 --- a/tests/test_find.rs +++ b/tests/test_find.rs @@ -519,6 +519,22 @@ fn find_printf_octal_escape_before_multibyte_char() { .stdout_only("\0€\n"); } +#[test] +fn find_printf_multibyte_char_after_directive() { + ucmd() + .args(&["./test_data/simple", "-maxdepth", "0", "-printf", "%€\\n"]) + .succeeds() + .stdout_only("€\n"); + ucmd() + .args(&["./test_data/simple", "-maxdepth", "0", "-printf", "\\€\\n"]) + .fails() + .stderr_contains("find: Invalid escape sequence"); + ucmd() + .args(&["./test_data/simple", "-maxdepth", "0", "-printf", "%A€"]) + .fails() + .stderr_contains("find: Invalid time specifier"); +} + #[cfg(unix)] #[test] fn find_perm() {