use clap::Parser;
use std::{fs::File, io::Read, path::PathBuf, process};
use tectonic_errors::prelude::*;
use tectonic_xetex_format::format::Format;
#[derive(Debug, Parser)]
#[clap(name = "decode", about = "Decode a Tectonic format file")]
struct Options {
#[command(subcommand)]
command: Commands,
}
impl Options {
fn execute(self) -> Result<()> {
match self.command {
Commands::Actives(c) => c.execute_actives(),
Commands::Catcodes(c) => c.execute_catcodes(),
Commands::ControlSequences(c) => c.execute(),
Commands::Strings(c) => c.execute_strings(),
}
}
}
#[derive(Debug, Parser)]
enum Commands {
Actives(GenericCommand),
Catcodes(GenericCommand),
#[command(name = "cseqs")]
ControlSequences(CseqsCommand),
Strings(GenericCommand),
}
#[derive(Debug, Eq, PartialEq, Parser)]
struct GenericCommand {
#[arg()]
path: PathBuf,
}
impl GenericCommand {
fn parse(&self) -> Result<Format> {
let mut file = File::open(&self.path)?;
let mut data = Vec::new();
file.read_to_end(&mut data)?;
Format::parse(&data[..])
}
fn execute_actives(self) -> Result<()> {
let fmt = self.parse()?;
let stdout = std::io::stdout();
let mut lock = stdout.lock();
fmt.dump_actives(&mut lock)?;
Ok(())
}
fn execute_catcodes(self) -> Result<()> {
let fmt = self.parse()?;
let stdout = std::io::stdout();
let mut lock = stdout.lock();
fmt.dump_catcodes(&mut lock)?;
Ok(())
}
fn execute_strings(self) -> Result<()> {
let fmt = self.parse()?;
let stdout = std::io::stdout();
let mut lock = stdout.lock();
fmt.dump_string_table(&mut lock)?;
Ok(())
}
}
#[derive(Debug, Eq, PartialEq, Parser)]
struct CseqsCommand {
#[arg(long = "extended", short = 'e')]
extended: bool,
#[arg()]
path: PathBuf,
}
impl CseqsCommand {
fn parse(&self) -> Result<Format> {
let mut file = File::open(&self.path)?;
let mut data = Vec::new();
file.read_to_end(&mut data)?;
Format::parse(&data[..])
}
fn execute(self) -> Result<()> {
let fmt = self.parse()?;
let stdout = std::io::stdout();
let mut lock = stdout.lock();
fmt.dump_cseqs(&mut lock, self.extended)?;
Ok(())
}
}
fn main() {
let options = Options::parse();
if let Err(e) = options.execute() {
eprintln!("error: {e}");
process::exit(1);
}
}