summaryrefslogtreecommitdiff
path: root/main.rs
blob: fa223741a1f27ff6283ec7345166bbc8cb89a664 (plain)
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
use std::io;
use std::io::{Seek, SeekFrom};
use std::fs;
use std::fmt::Write;
use std::io::Read;
use std::env;
use std::path::Path;

extern crate termios;
use termios::{Termios, TCSANOW, ECHO, ICANON, tcsetattr};

extern crate terminal_size;
use terminal_size::{Width, Height, terminal_size};

fn main() {
    println!("hello");
    if let Some((Width(w), Height(h))) = terminal_size() {
        if let Some(arg1) = env::args().nth(1) {
            println!("You would like to work with {}.", arg1);
            launch_interface(w, h, &arg1);
        } else {
            usage();
        }
    } else {
        println!("Wasn't able to get terminal dimensions for some reason");
    }
}

fn usage() {
    println!("usage: this_thing filename");
}

fn launch_interface(w: u16, h: u16, filename: &String) {
    println!("Launching interface with width {} and height {}...", w, h);

    // 4 = columns per group, 3 = xx xx xx xx , ...
    // + (x + 7) / 8 is for ascii at the end of line, rounded up to 8 characters
    // width = 8-20 + (3 * 4) * x + (x + 7) / 8
    // 8 * width = 87 + 57x
    // x = (8 * width -  87) / 57
    let hex_cols = (w * 8 - 87) / 57;
    println!("0x________: {}  {}", hex_cols, hex_cols);
    match fs::metadata(&filename) {
        Ok(fs_meta) => {
            println!("{} is {} bytes, and is it readable? {}", filename, fs_meta.len(), true);
            let termios = Termios::from_fd(0).unwrap();

            let mut new_termios = termios.clone();
            // fix terminal to not echo, thanks
            new_termios.c_lflag &= !(ICANON | ECHO);
            tcsetattr(0, TCSANOW, &mut new_termios).unwrap();

            interface_loop(w, h, filename);

            tcsetattr(0, TCSANOW, &termios).unwrap();
        },
        Err(e) => 
            println!("{} does not exist.", filename),
    }
}

fn interface_loop(w: u16, h: u16, filename: &String) {
    let mut cursor: u64 = 0;
    let mut buffer = [0; 0x200];
    populate_buf(filename, cursor, &mut buffer);
    render_interface(w, h, cursor, &buffer);

    let stdin = io::stdin();

    for byte in stdin.lock().bytes() {
        match byte {
            Ok(value) => {
                render_interface(w, h, cursor, &buffer);
            },
            Err(e) => {
                println!("Err: {}", e);
            }
        }
    }
}

fn ascii_or_dot(c: u8) -> u8 {
    let u = c as char;
    if (u >= 'a' && u <= 'z' || u >= '0' && u <= '9' || u >= 'A' && u <= 'Z' || u == '~' || u == '!' || u == '@' || u == '#' || u == '$' || u == '%' || u == '^' || u == '&' || u == '*' || u == '(' || u == ')' || u == '_' || u == '+' || u == '{' || u == '}' || u == '|' || u == ':' || u == '"' || u == '>' || u == '?' || u == '-' || u == '=' || u == '[' || u == ']' || u == '\\' || u == ';' || u == '\'' || u == '.' || u == '/' || u == '<' || u == ',' || u == '`') { c } else { '.' as u8 }
}

fn render_interface(w: u16, h: u16, cursor: u64, buffer: &[u8]) {
    println!("Dimensions: {}x{}    Cursor: {}   cursor_pos: ({}, {})", w, h, cursor, 0, 0);
    let addr_width = 8;
    // w = 10 + 1 + 1 + 4 * 3 * x + x + 1 + 4 * x
    // w = 13 + 17 * x
    // w - 13 / 17 = x
    let cols = (w - 13) / 17;
    let col_width = 4;
//    let ascii = bytes_width * cols;

    let mut idx: usize = 0;
    for i in 1..(h-1) {
        let mut hex_line = String::new();
        let mut ascii_line = String::new();
        for col in 0..cols {
            for c in 0..col_width {
                if (idx < buffer.len()) {
                    let chr = buffer[idx];
                    write!(&mut hex_line, "{:02x} ", chr).unwrap();
                    write!(&mut ascii_line, "{}", ascii_or_dot(chr) as char).unwrap();
                } else {
                    write!(&mut hex_line, "   ").unwrap();
                    write!(&mut ascii_line, " ").unwrap();
                }
                idx += 1;
            }
            write!(&mut hex_line, " ").unwrap();
        }

        let lineaddr = ((i as u64) - 1) * (cols as u64 * 4);
        let addr = if (lineaddr as usize) < buffer.len() {
            format!("0x{:08x}:", lineaddr)
        } else {
            "           ".to_string()
        };
        println!("{} {} {}", addr, hex_line, ascii_line);
    }
}

fn populate_buf(arg: &String, cursor: u64, buffer: &mut [u8]) {
    match fs::File::open(&arg) {
        Ok(mut fd) => {
            /*..*/
            fd.seek(SeekFrom::Start(cursor));
            fd.read(buffer);
            for b in buffer.into_iter() {
                print!("{:02x}", b);
            }
            println!("");
        },
        Err(_) =>
            println!("Failed to open {}", arg)
    }
}