#[allow(clippy::too_many_lines)]
pub fn process_ansi_c_content(chars: &[char], pos: &mut usize) -> String {
let mut out = String::new();
while *pos < chars.len() {
let c = chars[*pos];
if c == '\'' {
*pos += 1; return out;
}
if c == '\\' && *pos + 1 < chars.len() {
*pos += 1;
let esc = chars[*pos];
*pos += 1;
match esc {
'n' => out.push('\n'),
't' => out.push('\t'),
'r' => out.push('\r'),
'a' => out.push('\x07'),
'b' => out.push('\x08'),
'f' => out.push('\x0C'),
'v' => out.push('\x0B'),
'e' | 'E' => out.push('\x1B'),
'\\' => out.push('\\'),
'c' => {
if *pos < chars.len() {
let ctrl = chars[*pos];
*pos += 1;
let val = (ctrl as u32) & 0x1F;
if val > 0
&& let Some(ch) = char::from_u32(val)
{
out.push(ch);
}
} else {
out.push('\\');
out.push('c');
}
}
'\'' => {
out.push('\'');
out.push('\\');
out.push('\'');
out.push('\'');
return process_ansi_c_continue(chars, pos, out);
}
'"' => out.push('"'),
'x' => {
let before = *pos;
let hex = read_hex(chars, pos, 2);
if *pos == before {
out.push('\\');
out.push('x');
} else if hex == 0 {
skip_to_closing_quote(chars, pos);
return out;
} else if hex > 0x7F {
out.push('\u{FFFD}');
} else if let Some(ch) = char::from_u32(hex) {
if ch == '\x01' || ch == '\x7F' {
out.push('\x01');
}
out.push(ch);
}
}
'u' => {
let before = *pos;
let val = read_hex(chars, pos, 4);
if *pos == before {
out.push('\\');
out.push('u');
} else if val > 0
&& let Some(ch) = char::from_u32(val)
{
out.push(ch);
}
else if val == 0 && *pos > before {
skip_to_closing_quote(chars, pos);
return out;
}
}
'U' => {
let before = *pos;
let val = read_hex(chars, pos, 8);
if *pos == before {
out.push('\\');
out.push('U');
} else if val > 0
&& let Some(ch) = char::from_u32(val)
{
out.push(ch);
}
else if val == 0 && *pos > before {
skip_to_closing_quote(chars, pos);
return out;
}
}
'0'..='7' => {
let mut val = u32::from(esc as u8 - b'0');
for _ in 0..2 {
if *pos < chars.len() && chars[*pos] >= '0' && chars[*pos] <= '7' {
val = val * 8 + u32::from(chars[*pos] as u8 - b'0');
*pos += 1;
}
}
if val == 0 {
skip_to_closing_quote(chars, pos);
return out;
}
if let Some(ch) = char::from_u32(val) {
if ch == '\x01' || ch == '\x7F' {
out.push('\x01');
}
out.push(ch);
}
}
_ => {
out.push('\\');
out.push(esc);
}
}
} else {
out.push(c);
*pos += 1;
}
}
out
}
fn process_ansi_c_continue(chars: &[char], pos: &mut usize, mut out: String) -> String {
out.push_str(&process_ansi_c_content(chars, pos));
out
}
fn read_hex(chars: &[char], pos: &mut usize, max: usize) -> u32 {
let mut val = 0u32;
for _ in 0..max {
if *pos < chars.len() && chars[*pos].is_ascii_hexdigit() {
val = val * 16 + chars[*pos].to_digit(16).unwrap_or(0);
*pos += 1;
} else {
break;
}
}
val
}
fn skip_to_closing_quote(chars: &[char], pos: &mut usize) {
while *pos < chars.len() && chars[*pos] != '\'' {
*pos += 1;
}
if *pos < chars.len() {
*pos += 1;
}
}