autoconf-rs-cli 0.1.3

CLI harness for autoconf-rs tools: autoconf, autoheader, autom4te, autoreconf, aclocal, autoscan, autoupdate, ifnames
Documentation
//! autoheader binary — generate config.h.in from configure.ac.
//!
//! Panel mandate: consume trace events (not prescan) for AC_DEFINE detection.
//! Trace events are the data bus between autoconf, autoheader, and automake.
//!
//! Receipt family: AC.CLI.AUTOHEADER.*
//! Status: Phase 4 — trace-driven, autom4te --trace integrated.

use autoconf_rs_cli::read_input;
use autoconf_rs_core::trace::AutoconfEvent;
use autoconf_rs_core::M4Engine;
use std::env;
use std::process::ExitCode;

fn main() -> ExitCode {
    let args: Vec<String> = env::args().collect();
    let input_path = args.get(1).map(|s| s.as_str()).unwrap_or("configure.ac");

    // Handle --help and --version
    if input_path == "--help" || input_path == "-h" {
        println!("autoheader-rs {}", env!("CARGO_PKG_VERSION"));
        println!("Generate config.h.in from configure.ac");
        println!("Usage: autoheader [configure.ac]");
        println!("  -h, --help    Show this help");
        println!("  --version     Show version");
        return ExitCode::SUCCESS;
    }
    if input_path == "--version" {
        println!("autoheader-rs {}", env!("CARGO_PKG_VERSION"));
        return ExitCode::SUCCESS;
    }

    let input = match read_input(input_path) {
        Ok(s) => s,
        Err(e) => {
            eprintln!("autoheader: {}", e);
            return ExitCode::from(2);
        }
    };

    let mut engine = M4Engine::new();
    match engine.process(&input) {
        Ok(_output) => {
            // Panel architecture: consume trace events (source of truth)
            let trace_log = &engine.trace_log;

            // Extract AC_CONFIG_HEADERS from trace events
            let headers: Vec<&str> = trace_log
                .events
                .iter()
                .filter_map(|e| match e {
                    AutoconfEvent::ConfigHeader { output, .. } => Some(output.as_str()),
                    _ => None,
                })
                .collect();

            if headers.is_empty() {
                eprintln!("autoheader: no AC_CONFIG_HEADERS in configure.ac");
                eprintln!(
                    "  (checked {} trace events, 0 ConfigHeader found)",
                    trace_log.events.len()
                );
                return ExitCode::from(1);
            }

            // Extract AC_DEFINE from trace events
            let defines: Vec<(&str, Option<&str>)> = trace_log
                .events
                .iter()
                .filter_map(|e| match e {
                    AutoconfEvent::Define { name, value, .. } => {
                        Some((name.as_str(), value.as_deref()))
                    }
                    _ => None,
                })
                .collect();

            let header_file = headers.first().unwrap_or(&"config.h");

            println!(
                "/* {} — Generated by autoconf-rs autoheader (trace-driven). */",
                header_file
            );
            println!(
                "/* Source: {}{} trace events, {} AC_DEFINE, {} AC_CONFIG_HEADERS */",
                input_path,
                trace_log.events.len(),
                defines.len(),
                headers.len()
            );
            println!();

            if defines.is_empty() {
                println!("/* No AC_DEFINE calls found in trace events. */");
                println!("/* Try: autom4te --trace=AC_DEFINE {} */", input_path);
            } else {
                for (var, _value) in &defines {
                    println!("#undef {}", var);
                }
            }

            // Also emit AH_TEMPLATE-compatible output for autoheader consumers
            println!();
            println!("/* Template entries for autoheader compatibility */");
            for (var, value) in &defines {
                let desc = value.unwrap_or("");
                if !desc.is_empty() {
                    println!("@%:@undef {} /* {} */", var, desc);
                } else {
                    println!("@%:@undef {}", var);
                }
            }

            eprintln!(
                "autoheader: generated {} with {} #undef entries (trace-driven)",
                header_file,
                defines.len()
            );
            ExitCode::SUCCESS
        }
        Err(e) => {
            eprintln!("autoheader: {}", e);
            ExitCode::from(2)
        }
    }
}