mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-07-28 11:37:44 +00:00
expr: Fix error message for too big range quantifier index
This commit is contained in:
parent
6aeae43f3c
commit
07caa4867b
3 changed files with 78 additions and 30 deletions
|
@ -50,6 +50,8 @@ pub enum ExprError {
|
||||||
InvalidBracketContent,
|
InvalidBracketContent,
|
||||||
#[error("Trailing backslash")]
|
#[error("Trailing backslash")]
|
||||||
TrailingBackslash,
|
TrailingBackslash,
|
||||||
|
#[error("Regular expression too big")]
|
||||||
|
TooBigRangeQuantifierIndex,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UError for ExprError {
|
impl UError for ExprError {
|
||||||
|
|
|
@ -192,14 +192,15 @@ impl StringOp {
|
||||||
let _ = re_string.pop();
|
let _ = re_string.pop();
|
||||||
}
|
}
|
||||||
re_string.push(curr);
|
re_string.push(curr);
|
||||||
} else if is_valid_range_quantifier(&pattern_chars) {
|
} else {
|
||||||
|
// Check if the following section is a valid range quantifier
|
||||||
|
verify_range_quantifier(&pattern_chars)?;
|
||||||
|
|
||||||
re_string.push(curr);
|
re_string.push(curr);
|
||||||
// Set the lower bound of range quantifier to 0 if it is missing
|
// Set the lower bound of range quantifier to 0 if it is missing
|
||||||
if pattern_chars.peek() == Some(&',') {
|
if pattern_chars.peek() == Some(&',') {
|
||||||
re_string.push('0');
|
re_string.push('0');
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
return Err(ExprError::InvalidBracketContent);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => re_string.push(curr),
|
_ => re_string.push(curr),
|
||||||
|
@ -222,7 +223,7 @@ impl StringOp {
|
||||||
// "invalid repeat range {lower,upper}"
|
// "invalid repeat range {lower,upper}"
|
||||||
-123 => ExprError::InvalidBracketContent,
|
-123 => ExprError::InvalidBracketContent,
|
||||||
// "too big number for repeat range"
|
// "too big number for repeat range"
|
||||||
-201 => ExprError::InvalidBracketContent,
|
-201 => ExprError::TooBigRangeQuantifierIndex,
|
||||||
_ => ExprError::InvalidRegexExpression,
|
_ => ExprError::InvalidRegexExpression,
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
|
@ -277,7 +278,7 @@ where
|
||||||
/// - `r"\{,6\}"`
|
/// - `r"\{,6\}"`
|
||||||
/// - `r"\{3,6\}"`
|
/// - `r"\{3,6\}"`
|
||||||
/// - `r"\{,\}"`
|
/// - `r"\{,\}"`
|
||||||
fn is_valid_range_quantifier<I>(pattern_chars: &I) -> bool
|
fn verify_range_quantifier<I>(pattern_chars: &I) -> Result<(), ExprError>
|
||||||
where
|
where
|
||||||
I: Iterator<Item = char> + Clone,
|
I: Iterator<Item = char> + Clone,
|
||||||
{
|
{
|
||||||
|
@ -285,15 +286,19 @@ where
|
||||||
let mut quantifier = String::new();
|
let mut quantifier = String::new();
|
||||||
let mut pattern_chars_clone = pattern_chars.clone().peekable();
|
let mut pattern_chars_clone = pattern_chars.clone().peekable();
|
||||||
let Some(mut prev) = pattern_chars_clone.next() else {
|
let Some(mut prev) = pattern_chars_clone.next() else {
|
||||||
return false;
|
return Err(ExprError::UnmatchedOpeningBrace);
|
||||||
};
|
};
|
||||||
|
if pattern_chars_clone.peek().is_none() {
|
||||||
|
return Err(ExprError::UnmatchedOpeningBrace);
|
||||||
|
}
|
||||||
|
|
||||||
let mut prev_is_escaped = false;
|
let mut prev_is_escaped = false;
|
||||||
while let Some(curr) = pattern_chars_clone.next() {
|
while let Some(curr) = pattern_chars_clone.next() {
|
||||||
if prev == '\\' && curr == '}' && !prev_is_escaped {
|
if prev == '\\' && curr == '}' && !prev_is_escaped {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if pattern_chars_clone.peek().is_none() {
|
if pattern_chars_clone.peek().is_none() {
|
||||||
return false;
|
return Err(ExprError::UnmatchedOpeningBrace);
|
||||||
}
|
}
|
||||||
|
|
||||||
quantifier.push(prev);
|
quantifier.push(prev);
|
||||||
|
@ -302,19 +307,32 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if parsed quantifier is valid
|
// Check if parsed quantifier is valid
|
||||||
let is_valid_range_index = |s: &str| s.parse::<i32>().map_or(true, |x| x <= i16::MAX as i32);
|
|
||||||
let re = Regex::new(r"^(\d*,\d*|\d+)").expect("valid regular expression");
|
let re = Regex::new(r"^(\d*,\d*|\d+)").expect("valid regular expression");
|
||||||
if let Some(captures) = re.captures(&quantifier) {
|
if let Some(captures) = re.captures(&quantifier) {
|
||||||
let matched = captures.at(0).unwrap_or_default();
|
let matched = captures.at(0).unwrap_or_default();
|
||||||
match matched.split_once(',') {
|
match matched.split_once(',') {
|
||||||
None => is_valid_range_index(matched),
|
Some(("", "")) => Ok(()),
|
||||||
Some(("", "")) => true,
|
Some((x, "")) | Some(("", x)) => match x.parse::<i32>() {
|
||||||
Some((x, "")) => is_valid_range_index(x),
|
Ok(x) if x <= i16::MAX.into() => Ok(()),
|
||||||
Some(("", x)) => is_valid_range_index(x),
|
Ok(_) => Err(ExprError::TooBigRangeQuantifierIndex),
|
||||||
Some((f, l)) => f <= l && is_valid_range_index(f) && is_valid_range_index(l),
|
Err(_) => Err(ExprError::InvalidBracketContent),
|
||||||
|
},
|
||||||
|
Some((f, l)) => match (f.parse::<i32>(), l.parse::<i32>()) {
|
||||||
|
(Ok(f), Ok(l)) if f > l => Err(ExprError::InvalidBracketContent),
|
||||||
|
(Ok(f), Ok(l)) if f > i16::MAX.into() || l > i16::MAX.into() => {
|
||||||
|
Err(ExprError::TooBigRangeQuantifierIndex)
|
||||||
|
}
|
||||||
|
(Ok(_), Ok(_)) => Ok(()),
|
||||||
|
_ => Err(ExprError::InvalidBracketContent),
|
||||||
|
},
|
||||||
|
None => match matched.parse::<i32>() {
|
||||||
|
Ok(x) if x <= i16::MAX.into() => Ok(()),
|
||||||
|
Ok(_) => Err(ExprError::TooBigRangeQuantifierIndex),
|
||||||
|
Err(_) => Err(ExprError::InvalidBracketContent),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
false
|
Err(ExprError::InvalidBracketContent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -789,7 +807,7 @@ pub fn is_truthy(s: &NumOrStr) -> bool {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use crate::ExprError;
|
use crate::ExprError;
|
||||||
use crate::syntax_tree::is_valid_range_quantifier;
|
use crate::syntax_tree::verify_range_quantifier;
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
AstNode, AstNodeInner, BinOp, NumericOp, RelationOp, StringOp, check_posix_regex_errors,
|
AstNode, AstNodeInner, BinOp, NumericOp, RelationOp, StringOp, check_posix_regex_errors,
|
||||||
|
@ -999,19 +1017,47 @@ mod test {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_is_valid_range_quantifier() {
|
fn test_is_valid_range_quantifier() {
|
||||||
assert!(is_valid_range_quantifier(&"3\\}".chars()));
|
assert!(verify_range_quantifier(&"3\\}".chars()).is_ok());
|
||||||
assert!(is_valid_range_quantifier(&"3,\\}".chars()));
|
assert!(verify_range_quantifier(&"3,\\}".chars()).is_ok());
|
||||||
assert!(is_valid_range_quantifier(&",6\\}".chars()));
|
assert!(verify_range_quantifier(&",6\\}".chars()).is_ok());
|
||||||
assert!(is_valid_range_quantifier(&"3,6\\}".chars()));
|
assert!(verify_range_quantifier(&"3,6\\}".chars()).is_ok());
|
||||||
assert!(is_valid_range_quantifier(&",\\}".chars()));
|
assert!(verify_range_quantifier(&",\\}".chars()).is_ok());
|
||||||
assert!(is_valid_range_quantifier(&"3,6\\}anything".chars()));
|
assert!(verify_range_quantifier(&"32767\\}anything".chars()).is_ok());
|
||||||
assert!(!is_valid_range_quantifier(&"\\{3,6\\}".chars()));
|
assert_eq!(
|
||||||
assert!(!is_valid_range_quantifier(&"\\}".chars()));
|
verify_range_quantifier(&"\\{3,6\\}".chars()),
|
||||||
assert!(!is_valid_range_quantifier(&"".chars()));
|
Err(ExprError::InvalidBracketContent)
|
||||||
assert!(!is_valid_range_quantifier(&"3".chars()));
|
);
|
||||||
assert!(!is_valid_range_quantifier(&"3,".chars()));
|
assert_eq!(
|
||||||
assert!(!is_valid_range_quantifier(&",6".chars()));
|
verify_range_quantifier(&"\\}".chars()),
|
||||||
assert!(!is_valid_range_quantifier(&"3,6".chars()));
|
Err(ExprError::InvalidBracketContent)
|
||||||
assert!(!is_valid_range_quantifier(&",".chars()));
|
);
|
||||||
|
assert_eq!(
|
||||||
|
verify_range_quantifier(&"".chars()),
|
||||||
|
Err(ExprError::UnmatchedOpeningBrace)
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
verify_range_quantifier(&"3".chars()),
|
||||||
|
Err(ExprError::UnmatchedOpeningBrace)
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
verify_range_quantifier(&"3,".chars()),
|
||||||
|
Err(ExprError::UnmatchedOpeningBrace)
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
verify_range_quantifier(&",6".chars()),
|
||||||
|
Err(ExprError::UnmatchedOpeningBrace)
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
verify_range_quantifier(&"3,6".chars()),
|
||||||
|
Err(ExprError::UnmatchedOpeningBrace)
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
verify_range_quantifier(&",".chars()),
|
||||||
|
Err(ExprError::UnmatchedOpeningBrace)
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
verify_range_quantifier(&"32768\\}".chars()),
|
||||||
|
Err(ExprError::TooBigRangeQuantifierIndex)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1210,7 +1210,7 @@ mod gnu_expr {
|
||||||
.args(&["_", ":", "a\\{32768\\}"])
|
.args(&["_", ":", "a\\{32768\\}"])
|
||||||
.fails_with_code(2)
|
.fails_with_code(2)
|
||||||
.no_stdout()
|
.no_stdout()
|
||||||
.stderr_contains("Invalid content of \\{\\}");
|
.stderr_contains("Regular expression too big\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue