xinto 0.2.0

Intel Hexadecimal Object File Format Parser
Documentation
// Copyright (C) 2020 Guillaume Valadon <guillaume@valadon.net>

use std::fs::File;
use std::io::prelude::*; // used to get the BufRead trait
use std::io::BufReader;
use std::path::Path;

extern crate clap;
use clap::{App, Arg};

use xinto::{parse_record, Record, RecordParsingError};

fn main() -> Result<(), u8> {
    let matches = App::new("xinto - parse & convert Intel hexadecimal object file format")
        .arg(
            Arg::with_name("HEX_FILENAME")
                .help("hex file to convert")
                .required(true))
	.arg(
            Arg::with_name("convert")
	        .short("c")
                .help("convert the file to binary")
        )
        .get_matches();

    let filename = matches.value_of("HEX_FILENAME").unwrap();
    if !Path::new(filename).is_file() {
        eprintln!("Error: '{}' is not a valid file!", filename);
        return Err(1);
    }

    println!("{:?}", matches);
    println!("{:?}", matches.is_present("convert"));

    let file = File::open(filename).unwrap();
    let buf_reader = BufReader::new(file);

    let mut v = vec![];
    for (line_number, line) in buf_reader.lines().enumerate().map(|(ln, l)| (ln + 1, l)) {
        let record = match parse_record(&line.unwrap()) {
            Ok(r) => r,
            Err(RecordParsingError::MissingTag) => {
                eprintln!("Error at line {}: missing record mark!", line_number);
                return Err(1);
            }
            Err(e) => {
                eprintln!("Error at line {}: {:?}", line_number, e);
                return Err(1);
            }
        };
        v.push(record);
    }

    if !v.is_empty() {
        if *v.last().unwrap() != Record::end_of_file() {
            eprintln!("Error: last record is not a \"End of File Record\"!");
            return Err(1);
        }
    }

    println!("{}", serde_json::to_string(&v).or_else(|_| Err(3))?);

    Ok(())
}