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
use std::convert::TryFrom;
use cpclib_disc::amsdos::{AmsdosFile, AmsdosFileName};
use cpclib_disc::edsk::ExtendedDsk;
use cpclib_tokens::SaveType;
use super::report::SavedFile;
use super::Env;
use crate::error::AssemblerError;
#[derive(Debug, Clone)]
pub struct SaveCommand {
from: Option<i32>,
size: Option<i32>,
filename: String,
save_type: Option<SaveType>,
dsk_filename: Option<String>
}
impl SaveCommand {
pub fn new(
from: Option<i32>,
size: Option<i32>,
filename: String,
save_type: Option<SaveType>,
dsk_filename: Option<String>
) -> Self {
SaveCommand {
from,
size,
filename,
save_type,
dsk_filename
}
}
pub fn execute_on(&self, env: &Env) -> Result<SavedFile, AssemblerError> {
let from = match self.from {
Some(from) => from,
None => env.start_address().unwrap() as _
};
let size = match self.size {
Some(size) => size,
None => {
let stop = env.maximum_address();
(stop - from as u16) as _
}
};
let data = env.memory(from as _, size as _);
let object: either::Either<Vec<u8>, AmsdosFile> = match self.save_type {
Some(r#type) => {
let loading_address = from as u16;
let execution_address = match env.run_options {
Some((exec_address, _)) => exec_address,
None => loading_address
};
let amsdos_file = if r#type == SaveType::AmsdosBas {
AmsdosFile::basic_file_from_buffer(
&AmsdosFileName::try_from(self.filename.as_str())?,
&data
)?
}
else {
AmsdosFile::binary_file_from_buffer(
&AmsdosFileName::try_from(self.filename.as_str())?,
loading_address,
execution_address,
&data
)?
};
match r#type {
SaveType::AmsdosBin | SaveType::AmsdosBas => {
either::Left(amsdos_file.full_content().copied().collect::<Vec<u8>>())
}
SaveType::Dsk | SaveType::Tape => either::Right(amsdos_file)
}
}
None => either::Left(data)
};
match object {
either::Right(amsdos_file) => {
if let Some(dsk_filename) = &self.dsk_filename {
let mut dsk = if std::path::Path::new(dsk_filename.as_str()).exists() {
ExtendedDsk::open(dsk_filename)?
}
else {
ExtendedDsk::default()
};
dsk.add_amsdos_file(&amsdos_file)?;
dsk.save(dsk_filename)?;
}
else {
return Err(AssemblerError::InvalidArgument {
msg: "DSK parameter not provided".to_owned()
});
}
}
either::Left(data) => {
std::fs::write(&self.filename, &data).map_err(|e| {
AssemblerError::AssemblingError {
msg: format!(
"Error while saving \"{}\". {}",
&self.filename,
e.to_string()
)
}
})?;
}
}
Ok(SavedFile {
name: self.filename.clone(),
size: size as _
})
}
}