use autoconf_rs_cli::read_input;
use autoconf_rs_core::autom4te::Autom4teCache;
use autoconf_rs_core::M4Engine;
use std::env;
use std::path::{Path, PathBuf};
use std::process::ExitCode;
fn main() -> ExitCode {
let args: Vec<String> = env::args().collect();
let mut trace_patterns: Vec<String> = Vec::new();
let mut include_dirs: Vec<PathBuf> = Vec::new();
let mut input_path: Option<String> = None;
let mut show_traces = false;
let mut force = false;
let mut language = "Autoconf".to_string();
let mut cache_dir = PathBuf::from("autom4te.cache");
let mut i = 1;
while i < args.len() {
match args[i].as_str() {
"--force" | "-f" => force = true,
"--freeze" => {
eprintln!("autom4te: --freeze mode (will cache output)");
}
"--reload" => {
eprintln!("autom4te: --reload mode (will use cached output if fresh)");
}
"--language" | "-l" => {
i += 1;
if i < args.len() {
language = args[i].clone();
}
}
"--include" | "-I" => {
i += 1;
if i < args.len() {
include_dirs.push(PathBuf::from(&args[i]));
}
}
"--prepend-include" | "-B" => {
i += 1;
if i < args.len() {
include_dirs.insert(0, PathBuf::from(&args[i]));
}
}
"--cache" => {
i += 1;
if i < args.len() {
cache_dir = PathBuf::from(&args[i]);
}
}
a if a.starts_with("--trace") => {
if let Some(pattern) = a.strip_prefix("--trace=") {
trace_patterns.push(pattern.to_string());
}
show_traces = true;
}
a if !a.starts_with('-') => {
input_path = Some(a.to_string());
}
"-h" | "--help" => {
println!("autom4te-rs {}", env!("CARGO_PKG_VERSION"));
println!("Caching M4 wrapper for Autoconf");
println!("Usage: autom4te [OPTIONS] [file]");
println!(" -f, --force Force regeneration");
println!(" -I, --include DIR Add include directory");
println!(" -l, --language L Set language (Autoconf, M4sh, etc)");
println!(" --trace=M:F Emit trace events");
println!(" --cache DIR Set cache directory");
println!(" -h, --help Show this help");
println!(" --version Show version");
return ExitCode::SUCCESS;
}
"--version" => {
println!("autom4te-rs {}", env!("CARGO_PKG_VERSION"));
return ExitCode::SUCCESS;
}
_ => {
eprintln!("autom4te: unknown flag: {}", args[i]);
}
}
i += 1;
}
if include_dirs.is_empty() {
include_dirs.push(PathBuf::from("."));
}
let path_str = input_path.unwrap_or_else(|| "configure.ac".to_string());
let input_path = Path::new(&path_str);
let mut cache = Autom4teCache::new(&cache_dir);
cache.set_force(force);
if let Some(cached_output) = cache.lookup(input_path, &include_dirs, &language) {
if show_traces {
let traces = cache.get_traces(input_path, &language);
for trace in &traces {
println!("{}", trace);
}
} else {
print!("{}", cached_output);
}
return ExitCode::SUCCESS;
}
let input = match read_input(&path_str) {
Ok(s) => s,
Err(e) => {
eprintln!("autom4te: {}", e);
return ExitCode::from(2);
}
};
let mut engine = M4Engine::new();
match engine.process(&input) {
Ok(output) => {
let trace_lines: Vec<String> = engine
.trace_log
.emit_autom4te_traces()
.iter()
.map(|t| t.lines().next().unwrap_or(t).to_string())
.collect();
if show_traces {
if trace_patterns.is_empty() {
let traces = engine.trace_log.emit_autom4te_traces();
for trace in &traces {
println!("{}", trace);
}
eprintln!(
"autom4te: {} trace events emitted (from process)",
traces.len()
);
} else {
for pattern in &trace_patterns {
let parts: Vec<&str> = pattern.splitn(2, ':').collect();
let macro_name = parts[0];
let format_str = parts.get(1).copied().unwrap_or("$f:$l:$n:$1");
let structured = engine.trace_log.structured_traces();
let matching: Vec<_> = structured
.iter()
.filter(|(_, _, name, _)| name == macro_name)
.collect();
eprintln!(
"autom4te: trace {} => {} events",
macro_name,
matching.len()
);
for (file, line, name, args) in &matching {
println!(
"{}",
autoconf_rs_core::trace::TraceLog::format_trace(
file, *line, name, args, format_str
)
);
}
}
}
} else {
print!("{}", output);
cache.store(input_path, &include_dirs, &language, &output, &trace_lines);
}
if show_traces && !trace_lines.is_empty() {
cache.store(input_path, &include_dirs, &language, &output, &trace_lines);
}
ExitCode::SUCCESS
}
Err(e) => {
eprintln!("autom4te: {}", e);
ExitCode::from(2)
}
}
}