use super::shell::Word;
pub(crate) fn rewrite_grep_args(args: &[Word]) -> Option<Vec<String>> {
let mut recursive = false;
let mut options = Vec::new();
let mut positionals = Vec::new();
let mut after_double_dash = false;
let mut i = 0;
while i < args.len() {
let arg = args[i].text.as_str();
if after_double_dash {
positionals.push(arg.to_string());
i += 1;
continue;
}
if arg == "--" {
after_double_dash = true;
i += 1;
} else if let Some(next) = parse_grep_long(arg, args, i, &mut recursive, &mut options) {
i = next;
} else if arg.starts_with('-') && arg != "-" {
i = parse_grep_short(arg, i, &mut recursive, &mut options)?;
} else {
positionals.push(arg.to_string());
i += 1;
}
}
if !recursive || positionals.len() < 2 {
return None;
}
options.push("--".to_string());
options.extend(positionals);
Some(options)
}
fn parse_grep_long(
arg: &str,
args: &[Word],
index: usize,
recursive: &mut bool,
output: &mut Vec<String>,
) -> Option<usize> {
let (name, value) = arg
.split_once('=')
.map_or((arg, None), |(name, value)| (name, Some(value)));
match name {
"--recursive" | "--dereference-recursive" => {
if value.is_some() {
return None;
}
*recursive = true;
}
"--line-number" => {
if value.is_some() {
return None;
}
output.push("-n".to_string());
}
"--ignore-case" => {
if value.is_some() {
return None;
}
output.push("-i".to_string());
}
"--fixed-strings" => {
if value.is_some() {
return None;
}
output.push("-F".to_string());
}
"--binary-files" => {
match value {
Some("without-match") => {}
Some(_) => return None,
None => {
if args.get(index + 1).map(|w| w.text.as_str()) != Some("without-match") {
return None;
}
return Some(index + 2);
}
}
}
_ => return None,
}
Some(index + 1)
}
fn parse_grep_short(
arg: &str,
index: usize,
recursive: &mut bool,
output: &mut Vec<String>,
) -> Option<usize> {
let rest = arg.strip_prefix('-')?;
if rest.is_empty() {
return None;
}
for flag in rest.chars() {
match flag {
'R' | 'r' => *recursive = true,
'n' => output.push("-n".to_string()),
'i' => output.push("-i".to_string()),
'F' => output.push("-F".to_string()),
'I' => {}
_ => return None,
}
}
Some(index + 1)
}