Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Restructure #113

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ impl HexDiff {
}
}
fn parse_args(core: &mut Core, args: &[String]) -> Option<(u64, u64, u64)> {
if !(2..4).contains(&args.len()) {
expect_range(core, args.len() as u64, 2, 3);
return None;
}
let args: Vec<_> = args.iter().map(|s| str_to_num(s)).collect();
if args.len() == 2 {
let addr1 = core.get_loc();
Expand Down Expand Up @@ -102,10 +106,6 @@ impl Cmd for HexDiff {
}

fn run(&mut self, core: &mut Core, args: &[String]) {
if !(2..4).contains(&args.len()) {
expect_range(core, args.len() as u64, 2, 3);
return;
}
let Some((addr1, addr2, size)) = Self::parse_args(core, args) else {
return;
};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
use std::path::Path;

use super::HexDiff;
use crate::{CmdOps, Core, Writer};
use rair_io::IoMode;
use test_file::{operate_on_file, DATA};

use crate::{diff::hexdiff::HexDiff, CmdOps, Core, Writer};

#[test]
fn test_help() {
let mut core = Core::new_no_colors();
Expand Down
File renamed without changes.
39 changes: 39 additions & 0 deletions core/src/cmds/io/files/close_file.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
use crate::{error_msg, expect, str_to_num, Cmd, Core};

#[derive(Default)]
pub struct CloseFile;

impl CloseFile {
fn parse_args(core: &mut Core, args: &[String]) -> Option<u64> {
if args.len() != 1 {
expect(core, args.len() as u64, 1);
return None;
}
match str_to_num(&args[0]) {
Ok(hndl) => Some(hndl),
Err(e) => {
let err_str = format!("{e}");
error_msg(core, "Invalid hndl", &err_str);
None
}
}
}
}

impl Cmd for CloseFile {
fn commands(&self) -> &'static [&'static str] {
&["close"]
}
fn help_messages(&self) -> &'static [(&'static str, &'static str)] {
&[("[hndl]", "Close file with given hndl.")]
}
fn run(&mut self, core: &mut Core, args: &[String]) {
let Some(hndl) = Self::parse_args(core, args) else {
return;
};
if let Err(e) = core.io.close(hndl) {
let err_str = format!("{e}");
error_msg(core, "Failed to close file", &err_str);
}
}
}
65 changes: 65 additions & 0 deletions core/src/cmds/io/files/list_files.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
use yansi::Paint;

use crate::{expect, is_color, Cmd, Core};
use std::io::Write;

#[derive(Default)]
pub struct ListFiles;

impl ListFiles {
pub fn new(core: &mut Core) -> Self {
//TODO instead of hardcoding command name use it from [`Cmd`]
let env = core.env.clone();
env.write()
.add_str_with_cb(
"files.headerColor",
"color.6",
"Color used in the header of `files` command",
core,
is_color,
)
.unwrap();
Self
}
}

impl Cmd for ListFiles {
fn commands(&self) -> &'static [&'static str] {
&["files"]
}
fn help_messages(&self) -> &'static [(&'static str, &'static str)] {
&[("", "List all open files.")]
}
fn run(&mut self, core: &mut Core, args: &[String]) {
if !args.is_empty() {
expect(core, args.len() as u64, 0);
return;
}
let env = core.env.read();
let color = env.get_str("maps.headerColor").unwrap();
let (r, g, b) = env.get_color(color).unwrap();

writeln!(
core.stdout,
"{}",
"Handle\tStart address\tsize\t\tPermissions\tURI".rgb(r, g, b)
)
.unwrap();
for file in core.io.uri_iter() {
let perm = format!("{}", file.perm());
write!(
core.stdout,
"{}\t0x{:08x}\t0x{:08x}\t{}",
file.hndl(),
file.paddr_base(),
file.size(),
perm
)
.unwrap();
if perm.len() < 6 {
write!(core.stdout, "\t").unwrap();
}
writeln!(core.stdout, "\t{}", file.name()).unwrap();
}
}
}
11 changes: 11 additions & 0 deletions core/src/cmds/io/files/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
//! commands for opening, closing and listing files.
mod close_file;
mod list_files;
mod open_file;

#[cfg(test)]
mod tests;

pub use close_file::CloseFile;
pub use list_files::ListFiles;
pub use open_file::OpenFile;
87 changes: 87 additions & 0 deletions core/src/cmds/io/files/open_file.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
use crate::{error_msg, expect_range, str_to_num, Cmd, Core};
use rair_io::IoMode;

#[derive(Default)]
pub struct OpenFile;

impl OpenFile {
fn parse_three_args<'a>(
core: &mut Core,
arg0: &str,
arg1: &'a str,
arg2: &str,
) -> Option<(&'a str, IoMode, Option<u64>)> {
let perm: IoMode = match arg0.try_into() {
Ok(perm) => perm,
Err(e) => {
error_msg(core, "Failed to parse permission", &e);
return None;
}
};
let addr = match str_to_num(arg2) {
Ok(addr) => Some(addr),
Err(e) => {
let err_str = format!("{e}");
error_msg(core, "Failed to parse address", &err_str);
return None;
}
};
Some((arg1, perm, addr))
}
fn parse_two_args<'a>(
core: &mut Core,
arg0: &'a str,
arg1: &'a str,
) -> Option<(&'a str, IoMode, Option<u64>)> {
if let Ok(a) = str_to_num(arg1) {
Some((arg0, IoMode::READ, Some(a)))
} else {
let perm: IoMode = match arg0.try_into() {
Ok(perm) => perm,
Err(e) => {
error_msg(core, "Failed to parse permission", &e);
return None;
}
};
Some((arg1, perm, None))
}
}
fn parse_args<'a>(
core: &mut Core,
args: &'a [String],
) -> Option<(&'a str, IoMode, Option<u64>)> {
if args.len() > 3 || args.is_empty() {
expect_range(core, args.len() as u64, 1, 2);
return None;
}
if args.len() == 3 {
Self::parse_three_args(core, &args[0], &args[1], &args[2])
} else if args.len() == 2 {
Self::parse_two_args(core, &args[0], &args[1])
} else {
Some((&args[0], IoMode::READ, None))
}
}
}

impl Cmd for OpenFile {
fn commands(&self) -> &'static [&'static str] {
&["o", "open"]
}
fn help_messages(&self) -> &'static [(&'static str, &'static str)] {
&[("<Perm> [URI] <Addr>", "Open given URI using given optional permission (default to readonly) at given optional address.")]
}
fn run(&mut self, core: &mut Core, args: &[String]) {
let Some((uri, perm, addr)) = Self::parse_args(core, args) else {
return;
};
let result = match addr {
Some(addr) => core.io.open_at(uri, perm, addr),
None => core.io.open(uri, perm),
};
if let Err(e) = result {
let err_str = format!("{e}");
error_msg(core, "Failed to open file", &err_str);
}
}
}
149 changes: 149 additions & 0 deletions core/src/cmds/io/files/tests.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
use super::*;
use crate::{writer::Writer, Cmd, CmdOps, Core};
#[test]
fn test_docs() {
let mut core = Core::new_no_colors();
core.stderr = Writer::new_buf();
core.stdout = Writer::new_buf();
let open = OpenFile;
let close = CloseFile;
core.help("files");
open.help(&mut core);
close.help(&mut core);
assert_eq!(
core.stdout.utf8_string().unwrap(),
"Command: [files]\n\
Usage:\n\
files\tList all open files.\n\
Commands: [open | o]\n\
Usage:\n\
o <Perm> [URI] <Addr>\tOpen given URI using given optional permission (default to readonly) at given optional address.\n\
Command: [close]\n\
Usage:\n\
close [hndl]\tClose file with given hndl.\n"
);
assert_eq!(core.stderr.utf8_string().unwrap(), "");
}

#[test]
fn test_open_close_files() {
let mut core = Core::new_no_colors();
core.stderr = Writer::new_buf();
core.stdout = Writer::new_buf();
let mut open = OpenFile;
let mut close = CloseFile;
open.run(
&mut core,
&["b64://../testing_binaries/rio/base64/no_padding.b64".to_owned()],
);
open.run(&mut core, &["rw".to_owned(), "malloc://0x50".to_owned()]);
open.run(
&mut core,
&[
"c".to_owned(),
"../testing_binaries/rio/base64/one_pad.b64".to_owned(),
"0x5000".to_owned(),
],
);
open.run(
&mut core,
&[
"b64://../testing_binaries/rio/base64/no_padding.b64".to_owned(),
"0xa000".to_owned(),
],
);

core.run("files", &[]);
assert_eq!(
core.stdout.utf8_string().unwrap(),
"Handle\tStart address\tsize\t\tPermissions\tURI\n\
0\t0x00000000\t0x0000002d\tREAD\t\tb64://../testing_binaries/rio/base64/no_padding.b64\n\
1\t0x0000002d\t0x00000050\tWRITE | READ\tmalloc://0x50\n\
2\t0x00005000\t0x00000005\tCOW\t\t../testing_binaries/rio/base64/one_pad.b64\n\
3\t0x0000a000\t0x0000002d\tREAD\t\tb64://../testing_binaries/rio/base64/no_padding.b64\n"
);
assert_eq!(core.stderr.utf8_string().unwrap(), "");
core.stderr = Writer::new_buf();
core.stdout = Writer::new_buf();
close.run(&mut core, &["1".to_owned()]);
core.run("files", &[]);
assert_eq!(
core.stdout.utf8_string().unwrap(),
"Handle\tStart address\tsize\t\tPermissions\tURI\n\
0\t0x00000000\t0x0000002d\tREAD\t\tb64://../testing_binaries/rio/base64/no_padding.b64\n\
2\t0x00005000\t0x00000005\tCOW\t\t../testing_binaries/rio/base64/one_pad.b64\n\
3\t0x0000a000\t0x0000002d\tREAD\t\tb64://../testing_binaries/rio/base64/no_padding.b64\n"
);
assert_eq!(core.stderr.utf8_string().unwrap(), "");
}

#[test]
fn test_failing_parsing() {
let mut core = Core::new_no_colors();
core.stderr = Writer::new_buf();
core.stdout = Writer::new_buf();
let mut open = OpenFile;
open.run(&mut core, &["z".to_owned(), "malloc://0x50".to_owned()]);
open.run(
&mut core,
&[
"z".to_owned(),
"malloc://0x50".to_owned(),
"0x500".to_owned(),
],
);
open.run(
&mut core,
&[
"rw".to_owned(),
"malloc://0x50".to_owned(),
"0b500".to_owned(),
],
);

assert_eq!(core.stdout.utf8_string().unwrap(), "");
assert_eq!(
core.stderr.utf8_string().unwrap(),
"Error: Failed to parse permission\n\
Unknown Permission: `z`\n\
Error: Failed to parse permission\n\
Unknown Permission: `z`\n\
Error: Failed to parse address\n\
invalid digit found in string\n"
);
}

#[test]
fn test_arguments_count() {
let mut core = Core::new_no_colors();
core.stderr = Writer::new_buf();
core.stdout = Writer::new_buf();
let mut open = OpenFile;
let mut close = CloseFile;
open.run(&mut core, &[]);
core.run("files", &["test".to_owned()]);
close.run(&mut core, &[]);
assert_eq!(core.stdout.utf8_string().unwrap(), "");
assert_eq!(
core.stderr.utf8_string().unwrap(),
"Arguments Error: Expected between 1 and 2 arguments, found 0.\n\
Arguments Error: Expected 0 argument(s), found 1.\n\
Arguments Error: Expected 1 argument(s), found 0.\n"
);
}

#[test]
fn test_failed_open_close() {
let mut core = Core::new_no_colors();
core.stderr = Writer::new_buf();
core.stdout = Writer::new_buf();
let mut open = OpenFile;
let mut close = CloseFile;
open.run(&mut core, &["file_that_doesnt_exist".to_owned()]);
close.run(&mut core, &["5".to_owned()]);
assert_eq!(core.stdout.utf8_string().unwrap(), "");
let err = core.stderr.utf8_string().unwrap();
assert!(err.starts_with("Error: Failed to open file\n"));
// what in between is different between Windows and *Nix
assert!(err.ends_with("Error: Failed to close file\nHandle Does not exist.\n"));
}
Loading
Loading