pub fn skip_balanced_parens(bytes: &[u8], start: usize) -> usize {
let mut i = start;
let mut depth: usize = 1;
while i < bytes.len() && depth > 0 {
match bytes[i] {
b'\'' => {
i += 1;
while i < bytes.len() && bytes[i] != b'\'' {
i += 1;
}
if i < bytes.len() {
i += 1;
}
}
b'"' => {
i += 1;
while i < bytes.len() && bytes[i] != b'"' {
if bytes[i] == b'\\' && i + 1 < bytes.len() {
i += 2;
} else {
i += 1;
}
}
if i < bytes.len() {
i += 1;
}
}
b'\\' => {
if i + 1 < bytes.len() {
i += 2;
} else {
i += 1;
}
}
b'(' => {
depth += 1;
i += 1;
}
b')' => {
depth -= 1;
if depth > 0 {
i += 1;
}
}
_ => {
i += 1;
}
}
}
i
}
pub fn skip_balanced_braces(bytes: &[u8], start: usize) -> usize {
let mut i = start;
let mut depth: usize = 1;
while i < bytes.len() && depth > 0 {
match bytes[i] {
b'\'' => {
i += 1;
while i < bytes.len() && bytes[i] != b'\'' {
i += 1;
}
if i < bytes.len() {
i += 1;
}
}
b'"' => {
i += 1;
while i < bytes.len() && bytes[i] != b'"' {
if bytes[i] == b'\\' && i + 1 < bytes.len() {
i += 2;
} else {
i += 1;
}
}
if i < bytes.len() {
i += 1;
}
}
b'\\' => {
if i + 1 < bytes.len() {
i += 2;
} else {
i += 1;
}
}
b'{' => {
depth += 1;
i += 1;
}
b'}' => {
depth -= 1;
if depth > 0 {
i += 1;
}
}
_ => {
i += 1;
}
}
}
i
}
pub fn skip_balanced_double_parens(bytes: &[u8], start: usize) -> usize {
let mut i = start;
let mut depth: usize = 1;
while i + 1 < bytes.len() && depth > 0 {
match bytes[i] {
b'\'' => {
i += 1;
while i < bytes.len() && bytes[i] != b'\'' {
i += 1;
}
if i < bytes.len() {
i += 1;
}
}
b'"' => {
i += 1;
while i < bytes.len() && bytes[i] != b'"' {
if bytes[i] == b'\\' && i + 1 < bytes.len() {
i += 2;
} else {
i += 1;
}
}
if i < bytes.len() {
i += 1;
}
}
b'\\' => {
if i + 1 < bytes.len() {
i += 2;
} else {
i += 1;
}
}
b'(' => {
depth += 1;
i += 1;
}
b')' if bytes[i + 1] == b')' && depth == 1 => {
break;
}
b')' => {
depth -= 1;
i += 1;
}
_ => {
i += 1;
}
}
}
i
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_skip_balanced_parens_simple() {
let input = b"echo hello)";
assert_eq!(skip_balanced_parens(input, 0), 10);
}
#[test]
fn test_skip_balanced_parens_nested() {
let input = b"(inner) outer)";
assert_eq!(skip_balanced_parens(input, 0), 13);
}
#[test]
fn test_skip_balanced_parens_single_quoted() {
let input = b"')' real)";
assert_eq!(skip_balanced_parens(input, 0), 8);
}
#[test]
fn test_skip_balanced_parens_double_quoted() {
let input = b"\")(\" real)";
assert_eq!(skip_balanced_parens(input, 0), 9);
}
#[test]
fn test_skip_balanced_parens_backslash_escape() {
let input = b"\\) real)";
assert_eq!(skip_balanced_parens(input, 0), 7);
}
#[test]
fn test_skip_balanced_parens_unterminated_returns_len() {
let input = b"echo hello";
assert_eq!(skip_balanced_parens(input, 0), input.len());
}
#[test]
fn test_skip_balanced_double_parens_simple() {
let input = b"1 + 2))";
assert_eq!(skip_balanced_double_parens(input, 0), 5);
}
#[test]
fn test_skip_balanced_double_parens_nested() {
let input = b"(1 + 2) * 3))";
assert_eq!(skip_balanced_double_parens(input, 0), 11);
}
#[test]
fn test_skip_balanced_double_parens_unterminated_returns_len() {
let input = b"1 + 2 + expr";
assert_eq!(skip_balanced_double_parens(input, 0), input.len() - 1);
}
#[test]
fn test_skip_balanced_braces_simple() {
let input = b"var}";
assert_eq!(skip_balanced_braces(input, 0), 3);
}
#[test]
fn test_skip_balanced_braces_nested() {
let input = b"{inner} outer}";
assert_eq!(skip_balanced_braces(input, 0), 13);
}
#[test]
fn test_skip_balanced_braces_single_quoted() {
let input = b"var:-'}'}";
assert_eq!(skip_balanced_braces(input, 0), 8);
}
#[test]
fn test_skip_balanced_braces_double_quoted() {
let input = b"var:-\"}{\"}";
assert_eq!(skip_balanced_braces(input, 0), 9);
}
#[test]
fn test_skip_balanced_braces_backslash_escape() {
let input = b"var:-\\} real}";
assert_eq!(skip_balanced_braces(input, 0), 12);
}
#[test]
fn test_skip_balanced_braces_unterminated_returns_len() {
let input = b"var:-default";
assert_eq!(skip_balanced_braces(input, 0), input.len());
}
}