shk_parser 0.1.1

A parser for Stronghold Kingdoms attack formation files (.cas)
Documentation
#[cfg(feature = "cli")]
use clap::Parser;

use shk_parser::parse_formation_file;

#[cfg(feature = "cli")]
#[derive(Parser)]
#[command(name = "parse_formations")]
#[command(about = "A parser for Stronghold Kingdoms formation files (.cas)")]
struct Cli {
    /// Formation files to parse
    #[arg(help = "Formation file(s) to parse")]
    files: Vec<String>,

    /// Output format
    #[arg(short, long, default_value = "human")]
    format: String,

    /// Show detailed unit information
    #[arg(short, long)]
    verbose: bool,
}

#[cfg(feature = "cli")]
fn main() -> Result<(), Box<dyn std::error::Error>> {
    let cli = Cli::parse();

    let files = if cli.files.is_empty() {
        // Default test files if none provided
        vec![
            "AttackSetup_test2.cas".to_string(),
            "AttackSetup_test3.cas".to_string(),
            "AttackSetup_test4.cas".to_string(),
            "AttackSetup_test5.cas".to_string(),
            "AttackSetup_test6.cas".to_string(),
            "AttackSetup_testttt.cas".to_string(),
        ]
    } else {
        cli.files
    };

    for file in &files {
        if cli.verbose {
            println!("\n=== Parsing {file} ===");
        }

        match parse_formation_file(file) {
            Ok(units) => {
                if cli.format == "json" {
                    #[cfg(feature = "serde")]
                    {
                        let json = serde_json::to_string_pretty(&units)?;
                        println!("{json}");
                    }
                    #[cfg(not(feature = "serde"))]
                    {
                        eprintln!("JSON output requires the 'serde' feature");
                        std::process::exit(1);
                    }
                } else {
                    if cli.verbose {
                        println!("Successfully parsed {} units:", units.len());
                    }
                    for (i, unit) in units.iter().enumerate() {
                        if cli.verbose {
                            println!("  {}: {unit}", i + 1);
                        } else {
                            println!("{file}: {unit}");
                        }
                    }
                }
            }
            Err(e) => {
                eprintln!("Failed to parse {file}: {e}");
            }
        }
    }

    Ok(())
}

#[cfg(not(feature = "cli"))]
fn main() {
    // Parse all test files
    let test_files = [
        "formations/AttackSetup_test2.cas",
        "formations/AttackSetup_test3.cas",
        "formations/AttackSetup_test4.cas",
        "formations/AttackSetup_test5.cas",
        "formations/AttackSetup_test6.cas",
        "formations/AttackSetup_testttt.cas",
        "formations/AttackSetup_Corner_Breaker.cas",
    ];

    for file in &test_files {
        println!("\n=== Parsing {file} ===");

        match parse_formation_file(file) {
            Ok(units) => {
                println!("Successfully parsed {} units:", units.len());
                for (i, unit) in units.iter().enumerate() {
                    println!("  {}: {}", i + 1, unit);
                }
            }
            Err(e) => {
                eprintln!("Failed to parse {file}: {e}");
            }
        }
    }
}