textfsm-rust 0.3.1

Template-based state machine for parsing semi-formatted text based on Google's TextFSM
Documentation
//! Example: Using CliTable for automatic template selection
//!
//! CliTable uses an index file to automatically select the correct
//! template based on command and platform attributes.
//!
//! Run with: cargo run --example clitable_usage --features serde

use std::collections::HashMap;
use textfsm_rust::CliTable;

fn main() {
    // Sample template and index for demonstration
    let template_content = r#"
Value INTERFACE (\S+)
Value STATUS (up|down|administratively down)
Value IP_ADDRESS (\d+\.\d+\.\d+\.\d+)

Start
  ^Interface: ${INTERFACE} -> Continue
  ^  Status: ${STATUS}
  ^  IP: ${IP_ADDRESS} -> Record
"#;

    let index_content = r#"Template, Platform, Command
simple_interfaces.textfsm, demo, show interfaces
"#;

    // Create temp directory with template and index
    let temp_dir = std::env::temp_dir().join("textfsm_clitable_example");
    std::fs::create_dir_all(&temp_dir).expect("create temp dir");
    std::fs::write(temp_dir.join("index"), index_content).expect("write index");
    std::fs::write(temp_dir.join("simple_interfaces.textfsm"), template_content)
        .expect("write template");

    // Create CliTable from index
    let cli_table = CliTable::new(temp_dir.join("index"), &temp_dir)
        .expect("failed to create CliTable");

    // CLI output to parse
    let cli_output = r#"
Interface: GigabitEthernet0/0
  Status: up
  IP: 192.168.1.1
Interface: GigabitEthernet0/1
  Status: down
  IP: 10.0.0.1
Interface: Loopback0
  Status: up
  IP: 127.0.0.1
"#;

    // Set up attributes for template matching
    let mut attrs = HashMap::new();
    attrs.insert("Platform".into(), "demo".into());
    attrs.insert("Command".into(), "show interfaces".into());

    // Parse using automatic template selection
    let table = cli_table
        .parse_cmd(cli_output, &attrs)
        .expect("failed to parse");

    // Display results
    println!("Parsed {} interfaces:\n", table.len());
    println!("{}", table.formatted());

    // Demonstrate filtering
    println!("\nInterfaces that are UP:");
    let up_interfaces = table.filter(|row| row["STATUS"].as_string() == "up");
    for row in &up_interfaces {
        println!("  {} - {}", row["INTERFACE"].as_string(), row["IP_ADDRESS"].as_string());
    }

    // Demonstrate row access
    println!("\nFirst interface details:");
    if let Some(first) = table.get(0) {
        println!("  Interface: {}", first["INTERFACE"].as_string());
        println!("  Status: {}", first["STATUS"].as_string());
        println!("  IP: {}", first["IP_ADDRESS"].as_string());
    }

    // Cleanup
    std::fs::remove_dir_all(&temp_dir).ok();
}