mod environ;
use crate::action::AtomicAction;
use crate::host;
use crate::paths;
use crate::shell::tokens::env_refs;
use crate::shell::{ClassifyError, ShellContext, Sink};
pub(super) fn scan_payload(
payload: &str,
ctx: &ShellContext<'_>,
sink: &mut Sink,
) -> Result<(), ClassifyError> {
let is_separator =
|c: char| c.is_whitespace() || matches!(c, '(' | ')' | ',' | ';' | '\'' | '"' | '`');
let mut rest = payload;
while let Some(start) = rest.find(|c: char| !is_separator(c)) {
let tail = &rest[start..];
let end = tail.find(is_separator).unwrap_or(tail.len());
let raw = &tail[..end];
let quote = rest[..start]
.chars()
.last()
.filter(|c| matches!(c, '\'' | '"' | '`'));
rest = &tail[end..];
let in_string = quote.is_some_and(|q| rest.starts_with(q));
let called = rest.starts_with('(');
if paths::looks_like_path(raw) {
sink.read(ctx, raw)?;
} else if let Some(host) = host::of_word(raw).filter(|_| !called) {
sink.push(if raw.contains("://") || in_string {
AtomicAction::Net { host }
} else {
AtomicAction::NetWord { host }
})?;
}
for name in env_refs(raw) {
sink.push(AtomicAction::EnvRead { name })?;
}
}
let (names, whole) = environ::reads(payload);
for name in names {
sink.push(AtomicAction::EnvRead { name })?;
}
if let Some(expression) = whole {
sink.push(AtomicAction::Shell {
argv: vec!["@env-dump".to_owned(), expression.to_owned()],
})?;
}
Ok(())
}