//
// Syd: rock-solid unikernel
// src/syd-net.rs: Aggregate IP networks
//
// Copyright (c) 2024 Ali Polatel <alip@chesswob.org>
//
// SPDX-License-Identifier: GPL-3.0-or-later

use std::{
    fs::File,
    io::{stdin, BufReader},
};

use getargs::{Opt, Options};
use nix::errno::Errno;
use syd::{err::SydResult, sandbox::Sandbox};

// Set global allocator to mimalloc.
#[global_allocator]
static GLOBAL: mimalloc2_rust::GlobalMiMalloc = mimalloc2_rust::GlobalMiMalloc;

fn main() -> SydResult<()> {
    syd::set_sigpipe_dfl()?;

    // Configure mimalloc.
    syd::configure_mimalloc();

    let args = std::env::args().skip(1).collect::<Vec<_>>();
    let args: &'static Vec<String> = Box::leak(Box::new(args));
    let mut opts = Options::new(args.iter().map(String::as_str));

    #[allow(clippy::never_loop)]
    while let Some(opt) = opts.next_opt()? {
        match opt {
            Opt::Short('h') => {
                help();
                return Ok(());
            }
            Opt::Short(opt) => {
                eprintln!("Unknown option: -{opt}!");
                help();
                return Err(Errno::EINVAL.into());
            }
            Opt::Long(opt) => {
                eprintln!("Unknown option: --{opt}!");
                help();
                return Err(Errno::EINVAL.into());
            }
        }
    }

    let mut sin = true;
    let mut syd = Sandbox::new();
    for path in opts.positionals() {
        sin = false;

        let file = File::open(path)?;
        syd.parse_netset(BufReader::new(file))?;
    }

    if sin {
        let file = stdin();
        syd.parse_netset(BufReader::new(file))?;
    }

    syd.rule_agg_block("")?;
    for addr in syd.block4() {
        println!("{addr}");
    }
    for addr in syd.block6() {
        println!("{addr}");
    }

    Ok(())
}

fn help() {
    println!("Usage: syd-net [-h] <path>...");
    println!("Tool to aggregate IP networks.");
    println!("Reads IP networks from the given list of paths.");
    println!("Given no arguments, reads from standard input.");
}
