summaryrefslogblamecommitdiff
path: root/src/configuration/from_arguments.rs
blob: a62813cb3fdf88c9ff017bd02348caf80e3e03de (plain) (tree)
























































































































































                                                                                                                              
/*
	Copyright 2023-2024 Gabriel Bjørnager Jensen.

	This file is part of eAS.

	eAS is free software: you can redistribute it
	and/or modify it under the terms of the GNU
	General Public License as published by the Free
	Software Foundation, either version 3 of the
	License, or (at your option) any later version.

	eAS is distributed in the hope that it will
	be useful, but WITHOUT ANY WARRANTY; without
	even the implied warranty of MERCHANTABILITY or
	FITNESS FOR A PARTICULAR PURPOSE. See the GNU
	General Public License for more details.

	You should have received a copy of the GNU
	General Public License along with eAS. If not,
	see <https://www.gnu.org/licenses/>.
*/

use crate::app::App;
use crate::configuration::Configuration;
use crate::encoding::Encoding;
use crate::error::Error;
use crate::processor::Processor;
use crate::format::Format;

use std::env::args;
use std::str::FromStr;

struct ConfigurationTemporary {
	pub input:     Option<String>,
	pub output:    Option<String>,

	pub encoding:  Option<String>,
	pub processor: Option<String>,
	pub format:    Option<String>,
}

impl Configuration {
	pub fn from_arguments() -> Result<Self, Error> {
		if args().len() < 0x2 { return Err(Error::MissingInputFile) };

		let mut temporary = ConfigurationTemporary {
			input:     None,
			output:    None,

			encoding:  None,
			processor: None,
			format:    None,
		};

		for argument in args().skip(0x1) {
			// Skip the first, we assume that it's just the
			// executable invoked.

			if argument.is_empty() { continue };
			let argument: Vec<char> = argument.chars().collect();

			if argument[0x0] != '-' {
				// This argument is the input path.

				temporary.input = Some(argument.into_iter().collect());
				continue;
			}

			match argument.get(0x1) {
				Some('-') => handle_long_argument( &mut temporary, argument.into_iter().skip(0x2).collect())?,
				Some(_)   => handle_short_argument(&mut temporary, &argument[0x1..])?,

				_ => return Err(Error::MissingShortArgument),
			}
		}

		// Check if any of the mandatory parameters have
		// been set.
		if temporary.input.is_none()     { return Err(Error::MissingInputFile) };
		if temporary.processor.is_none() { return Err(Error::MissingTargetProcessor) };

		// The output path defaults to "a.out".
		// TODO: Do something better.
		if temporary.output.is_none() { temporary.output = Some(String::from("a.out")) };

		let processor = Processor::from_str(&temporary.processor.unwrap())?;

		let encoding = match temporary.encoding {
			Some(format) => Encoding::from_str(&format)?,
			_            => Encoding::default(),
		};

		let format = match temporary.format {
			Some(format) => Format::from_str(&format)?,
			_            => Format::default(),
		};

		return Ok(Self {
			input:  temporary.input.unwrap(),
			output: temporary.output.unwrap(),

			encoding,
			processor,
			format,
		});
	}
}

fn handle_short_argument(temporary: &mut ConfigurationTemporary, argument: &[char]) -> Result<(), Error> {
	macro_rules! use_remainder_as_value {
		($argument: expr, $index: expr) => {{
			let argument: &[char] = $argument;
			let index:    usize   = $index;

			let next_index = index + 0x1;

			if argument.len() <= next_index {
				// There are no more characters, and thus no values.
				let c = argument[index];
				Err(Error::MissingShortValue(c))
			} else {
				let value: String = argument[next_index..].iter().collect();
				Ok(value)
			}
		}};
	}

	for (index, c) in argument.iter().enumerate() {
		match c {
			'c' => { temporary.encoding  = Some(use_remainder_as_value!(&argument, index)?); break; },
			'f' => { temporary.format    = Some(use_remainder_as_value!(&argument, index)?); break; },
			'm' => { temporary.processor = Some(use_remainder_as_value!(&argument, index)?); break; },
			'o' => { temporary.output    = Some(use_remainder_as_value!(&argument, index)?); break; },

			'h' => App::print_help(),

			_ => return Err(Error::InvalidShortParameter(*c)),
		};
	}

	return Ok(());
}

fn handle_long_argument(_temporary: &mut ConfigurationTemporary, argument: String) -> Result<(), Error> {
	match argument.as_str() {
		"help"    => App::print_help(),
		"version" => App::print_version(),

		_ => return Err(Error::InvalidLongParameter(argument.to_string())),
	};

	return Ok(());
}