Skip to content

Commit a041eee

Browse files
committed
Added hexdump and cat.
Also moved the code into a method so we can use ?. Although ? is a pain when your objects cannot safely be dropped.
1 parent 0578d4e commit a041eee

File tree

1 file changed

+185
-76
lines changed

1 file changed

+185
-76
lines changed

examples/shell.rs

Lines changed: 185 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,158 @@ use crate::linux::{Clock, LinuxBlockDevice};
1010

1111
mod linux;
1212

13-
struct State {
13+
struct VolumeState {
1414
directory: Directory,
1515
volume: Volume,
16+
path: Vec<String>,
17+
}
18+
19+
struct Context {
20+
volume_mgr: VolumeManager<LinuxBlockDevice, Clock, 8, 8, 4>,
21+
volumes: [Option<VolumeState>; 4],
22+
current_volume: usize,
23+
}
24+
25+
impl Context {
26+
fn current_path(&self) -> Vec<String> {
27+
let Some(s) = &self.volumes[self.current_volume] else {
28+
return vec![];
29+
};
30+
s.path.clone()
31+
}
32+
33+
fn process_line(&mut self, line: &str) -> Result<(), Error<std::io::Error>> {
34+
if line == "help" {
35+
println!("Commands:");
36+
println!("\thelp -> this help text");
37+
println!("\t<volume>: -> change volume/partition");
38+
println!("\tdir -> do a directory listing");
39+
println!("\tstat -> print volume manager status");
40+
println!("\tcat <file> -> print a text file");
41+
println!("\thexdump <file> -> print a binary file");
42+
println!("\tcd .. -> go up a level");
43+
println!("\tcd <dir> -> change into <dir>");
44+
println!("\tquit -> exits the program");
45+
} else if line == "0:" {
46+
self.current_volume = 0;
47+
} else if line == "1:" {
48+
self.current_volume = 1;
49+
} else if line == "2:" {
50+
self.current_volume = 2;
51+
} else if line == "3:" {
52+
self.current_volume = 3;
53+
} else if line == "stat" {
54+
println!("Status:\n{:#?}", self.volume_mgr);
55+
} else if line == "dir" {
56+
let Some(s) = &self.volumes[self.current_volume] else {
57+
println!("That volume isn't available");
58+
return Ok(());
59+
};
60+
self.volume_mgr.iterate_dir(s.directory, |entry| {
61+
println!(
62+
"{:12} {:9} {} {}",
63+
entry.name,
64+
entry.size,
65+
entry.mtime,
66+
if entry.attributes.is_directory() {
67+
"<DIR>"
68+
} else {
69+
""
70+
}
71+
);
72+
})?;
73+
} else if let Some(arg) = line.strip_prefix("cd ") {
74+
let Some(s) = &mut self.volumes[self.current_volume] else {
75+
println!("This volume isn't available");
76+
return Ok(());
77+
};
78+
let d = self.volume_mgr.open_dir(s.directory, arg)?;
79+
self.volume_mgr.close_dir(s.directory)?;
80+
s.directory = d;
81+
if arg == ".." {
82+
s.path.pop();
83+
} else {
84+
s.path.push(arg.to_owned());
85+
}
86+
} else if let Some(arg) = line.strip_prefix("cat ") {
87+
let Some(s) = &mut self.volumes[self.current_volume] else {
88+
println!("This volume isn't available");
89+
return Ok(());
90+
};
91+
let f = self.volume_mgr.open_file_in_dir(
92+
s.directory,
93+
arg,
94+
embedded_sdmmc::Mode::ReadOnly,
95+
)?;
96+
let mut inner = || -> Result<(), Error<std::io::Error>> {
97+
let mut data = Vec::new();
98+
while !self.volume_mgr.file_eof(f)? {
99+
let mut buffer = vec![0u8; 65536];
100+
let n = self.volume_mgr.read(f, &mut buffer)?;
101+
// read n bytes
102+
data.extend_from_slice(&buffer[0..n]);
103+
println!("Read {} bytes, making {} total", n, data.len());
104+
}
105+
if let Ok(s) = std::str::from_utf8(&data) {
106+
println!("{}", s);
107+
} else {
108+
println!("I'm afraid that file isn't UTF-8 encoded");
109+
}
110+
Ok(())
111+
};
112+
let r = inner();
113+
self.volume_mgr.close_file(f)?;
114+
r?;
115+
} else if let Some(arg) = line.strip_prefix("hexdump ") {
116+
let Some(s) = &mut self.volumes[self.current_volume] else {
117+
println!("This volume isn't available");
118+
return Ok(());
119+
};
120+
let f = self.volume_mgr.open_file_in_dir(
121+
s.directory,
122+
arg,
123+
embedded_sdmmc::Mode::ReadOnly,
124+
)?;
125+
let mut inner = || -> Result<(), Error<std::io::Error>> {
126+
let mut data = Vec::new();
127+
while !self.volume_mgr.file_eof(f)? {
128+
let mut buffer = vec![0u8; 65536];
129+
let n = self.volume_mgr.read(f, &mut buffer)?;
130+
// read n bytes
131+
data.extend_from_slice(&buffer[0..n]);
132+
println!("Read {} bytes, making {} total", n, data.len());
133+
}
134+
for (idx, chunk) in data.chunks(16).enumerate() {
135+
print!("{:08x} | ", idx * 16);
136+
for b in chunk {
137+
print!("{:02x} ", b);
138+
}
139+
for _padding in 0..(16 - chunk.len()) {
140+
print!(" ");
141+
}
142+
print!("| ");
143+
for b in chunk {
144+
print!(
145+
"{}",
146+
if b.is_ascii_graphic() {
147+
*b as char
148+
} else {
149+
'.'
150+
}
151+
);
152+
}
153+
println!();
154+
}
155+
Ok(())
156+
};
157+
let r = inner();
158+
self.volume_mgr.close_file(f)?;
159+
r?;
160+
} else {
161+
println!("Unknown command {line:?} - try 'help' for help");
162+
}
163+
Ok(())
164+
}
16165
}
17166

18167
fn main() -> Result<(), Error<std::io::Error>> {
@@ -22,29 +171,33 @@ fn main() -> Result<(), Error<std::io::Error>> {
22171
let print_blocks = args.find(|x| x == "-v").map(|_| true).unwrap_or(false);
23172
println!("Opening '{filename}'...");
24173
let lbd = LinuxBlockDevice::new(filename, print_blocks).map_err(Error::DeviceError)?;
25-
let mut volume_mgr: VolumeManager<LinuxBlockDevice, Clock, 8, 8, 4> =
26-
VolumeManager::new_with_limits(lbd, Clock, 100);
27174
let stdin = std::io::stdin();
28-
let mut volumes: [Option<State>; 4] = [None, None, None, None];
175+
176+
let mut ctx = Context {
177+
volume_mgr: VolumeManager::new_with_limits(lbd, Clock, 100),
178+
volumes: [None, None, None, None],
179+
current_volume: 0,
180+
};
29181

30182
let mut current_volume = None;
31183
for volume_no in 0..4 {
32-
match volume_mgr.open_volume(VolumeIdx(volume_no)) {
184+
match ctx.volume_mgr.open_volume(VolumeIdx(volume_no)) {
33185
Ok(volume) => {
34186
println!("Volume # {}: found", volume_no,);
35-
match volume_mgr.open_root_dir(volume) {
187+
match ctx.volume_mgr.open_root_dir(volume) {
36188
Ok(root_dir) => {
37-
volumes[volume_no] = Some(State {
189+
ctx.volumes[volume_no] = Some(VolumeState {
38190
directory: root_dir,
39191
volume,
192+
path: vec![],
40193
});
41194
if current_volume.is_none() {
42195
current_volume = Some(volume_no);
43196
}
44197
}
45198
Err(e) => {
46199
println!("Failed to open root directory: {e:?}");
47-
volume_mgr.close_volume(volume).expect("close volume");
200+
ctx.volume_mgr.close_volume(volume).expect("close volume");
48201
}
49202
}
50203
}
@@ -54,95 +207,51 @@ fn main() -> Result<(), Error<std::io::Error>> {
54207
}
55208
}
56209

57-
let Some(mut current_volume) = current_volume else {
58-
println!("No volumes found in file. Sorry.");
59-
return Ok(());
210+
match current_volume {
211+
Some(n) => {
212+
// Default to the first valid partition
213+
ctx.current_volume = n;
214+
}
215+
None => {
216+
println!("No volumes found in file. Sorry.");
217+
return Ok(());
218+
}
60219
};
61220

62221
loop {
63-
print!("{}:> ", current_volume);
222+
print!("{}:/", ctx.current_volume);
223+
print!("{}", ctx.current_path().join("/"));
224+
print!("> ");
64225
std::io::stdout().flush().unwrap();
65226
let mut line = String::new();
66227
stdin.read_line(&mut line)?;
67228
let line = line.trim();
68229
if line == "quit" {
69230
break;
70-
} else if line == "help" {
71-
println!("Commands:");
72-
println!("\thelp -> this help text");
73-
println!("\t<volume>: -> change volume/partition");
74-
println!("\tdir -> do a directory listing");
75-
println!("\tquit -> exits the program");
76-
} else if line == "0:" {
77-
current_volume = 0;
78-
} else if line == "1:" {
79-
current_volume = 1;
80-
} else if line == "2:" {
81-
current_volume = 2;
82-
} else if line == "3:" {
83-
current_volume = 3;
84-
} else if line == "stat" {
85-
println!("Status:\n{volume_mgr:#?}");
86-
} else if line == "dir" {
87-
let Some(s) = &volumes[current_volume] else {
88-
println!("That volume isn't available");
89-
continue;
90-
};
91-
let r = volume_mgr.iterate_dir(s.directory, |entry| {
92-
println!(
93-
"{:12} {:9} {} {}",
94-
entry.name,
95-
entry.size,
96-
entry.mtime,
97-
if entry.attributes.is_directory() {
98-
"<DIR>"
99-
} else {
100-
""
101-
}
102-
);
103-
});
104-
handle("iterating directory", r);
105-
} else if let Some(arg) = line.strip_prefix("cd ") {
106-
let Some(s) = &mut volumes[current_volume] else {
107-
println!("This volume isn't available");
108-
continue;
109-
};
110-
match volume_mgr.open_dir(s.directory, arg) {
111-
Ok(d) => {
112-
let r = volume_mgr.close_dir(s.directory);
113-
handle("closing old directory", r);
114-
s.directory = d;
115-
}
116-
Err(e) => {
117-
handle("changing directory", Err(e));
118-
}
119-
}
120-
} else {
121-
println!("Unknown command {line:?} - try 'help' for help");
231+
} else if let Err(e) = ctx.process_line(line) {
232+
println!("Error: {:?}", e);
122233
}
123234
}
124235

125-
for (idx, s) in volumes.into_iter().enumerate() {
236+
for (idx, s) in ctx.volumes.into_iter().enumerate() {
126237
if let Some(state) = s {
238+
println!("Closing current dir for {idx}...");
239+
let r = ctx.volume_mgr.close_dir(state.directory);
240+
if let Err(e) = r {
241+
println!("Error closing directory: {e:?}");
242+
}
127243
println!("Unmounting {idx}...");
128-
let r = volume_mgr.close_dir(state.directory);
129-
handle("closing directory", r);
130-
let r = volume_mgr.close_volume(state.volume);
131-
handle("closing volume", r);
132-
println!("Unmounted {idx}!");
244+
let r = ctx.volume_mgr.close_volume(state.volume);
245+
if let Err(e) = r {
246+
println!("Error closing volume: {e:?}");
247+
}
133248
}
134249
}
135250

136251
println!("Bye!");
137252
Ok(())
138253
}
139254

140-
fn handle(operation: &str, r: Result<(), Error<std::io::Error>>) {
141-
if let Err(e) = r {
142-
println!("Error {operation}: {e:?}");
143-
}
144-
}
145-
146255
// ****************************************************************************
147256
//
148257
// End Of File

0 commit comments

Comments
 (0)