use super::lexer::{lex, remove_ranges};
#[cfg(test)]
pub(crate) fn strip_quoted_heredoc_bodies(command: &str) -> String {
strip_for_analysis(command, true, false)
}
pub fn strip_all_heredoc_bodies(command: &str) -> String {
strip_for_analysis(command, false, false)
}
pub(crate) fn strip_for_analysis(command: &str, quoted_only: bool, comments: bool) -> String {
if !command.contains("<<") && (!comments || !command.contains('#')) {
return command.to_string();
}
let lexed = lex(command);
let mut ranges: Vec<_> = lexed
.heredocs
.iter()
.filter(|h| !quoted_only || h.quoted)
.map(|h| h.body.clone())
.collect();
if comments {
ranges.extend(lexed.comments);
}
remove_ranges(command, ranges)
}
pub fn heredoc_delims(line: &str, quoted_only: bool) -> Vec<String> {
if !line.contains("<<") {
return Vec::new();
}
lex(line)
.heredocs
.into_iter()
.filter(|h| !quoted_only || h.quoted)
.map(|h| h.delim)
.collect()
}
pub fn read_heredoc_delim(bytes: &[u8], start: usize) -> Option<(String, bool, usize)> {
let len = bytes.len();
let mut i = start;
let mut name: Vec<u8> = Vec::new();
let mut quoted = false;
while i < len {
match bytes[i] {
b'\'' => {
quoted = true;
i += 1;
while i < len && bytes[i] != b'\'' {
name.push(bytes[i]);
i += 1;
}
i += usize::from(i < len); }
b'"' => {
quoted = true;
i += 1;
while i < len && bytes[i] != b'"' {
name.push(bytes[i]);
i += 1;
}
i += usize::from(i < len);
}
b'\\' => {
quoted = true;
i += 1;
if i < len {
name.push(bytes[i]);
i += 1;
}
}
b' ' | b'\t' | b'<' | b'>' | b'|' | b'&' | b';' => break,
c => {
name.push(c);
i += 1;
}
}
}
if name.is_empty() {
None
} else {
Some((String::from_utf8_lossy(&name).into_owned(), quoted, i))
}
}
#[cfg(test)]
pub(crate) fn strip_comments(command: &str) -> String {
if !command.contains('#') {
return command.to_string();
}
remove_ranges(command, lex(command).comments)
}