summaryrefslogtreecommitdiff
path: root/src/configuration/from_arguments.rs
blob: a62813cb3fdf88c9ff017bd02348caf80e3e03de (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
/*
	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(());
}