diff --git a/kernel/src/shell.rs b/kernel/src/shell.rs index 7e7b2d9..e85e6bb 100644 --- a/kernel/src/shell.rs +++ b/kernel/src/shell.rs @@ -1,6 +1,7 @@ //! Kernel shell use alloc::string::String; +use alloc::vec::Vec; use crate::fs::{ROOT_INODE, INodeExt}; use crate::process::*; use crate::thread; @@ -21,10 +22,11 @@ pub fn run_user_shell() { pub extern fn shell(_arg: usize) -> ! { let files = ROOT_INODE.list().unwrap(); println!("Available programs: {:?}", files); + let mut history = Vec::new(); loop { print!(">> "); - let cmd = get_line(); + let cmd = get_line(&mut history); if cmd == "" { continue; } @@ -39,29 +41,142 @@ pub extern fn shell(_arg: usize) -> ! { } } -fn get_line() -> String { - let mut s = String::new(); +const BEL: u8 = 0x07u8; +const BS: u8 = 0x08u8; +const LF: u8 = 0x0au8; +const CR: u8 = 0x0du8; +const ESC: u8 = 0x1bu8; +const DEL: u8 = 0x7fu8; + +fn get_line(history: &mut Vec>) -> String { + let mut cursor = 0; + let mut line_vec = Vec::with_capacity(512); + let mut history_index = history.len(); loop { - let c = get_char(); - match c { - '\u{8}' | '\u{7f}' /* '\b' */ => { - if s.pop().is_some() { - print!("\u{7f}"); + match get_char() { + BS | DEL => { + // Backspace + if cursor > 0 { + cursor -= 1; + line_vec.remove(cursor); + + put_char(BS); + for byte in &line_vec[cursor..] { + put_char(*byte); + } + put_char(b' '); + for _i in cursor..line_vec.len() { + put_char(ESC); + put_char(b'['); + put_char(b'D'); + } + put_char(ESC); + put_char(b'['); + put_char(b'D'); + } else { + put_char(BEL); } } - ' '...'\u{7e}' => { - s.push(c); - print!("{}", c); + CR | LF => { + // Return + put_char(CR); + put_char(LF); + break; } - '\n' | '\r' => { - print!("\n"); - return s; + ESC => { + match get_char() { + b'[' => { + match get_char() { + b'D' => { + // Left arrow + if cursor > 0 { + cursor -= 1; + put_char(ESC); + put_char(b'['); + put_char(b'D'); + } else { + put_char(BEL); + } + } + b'C' => { + // Right arrow + if cursor < line_vec.len() { + cursor += 1; + put_char(ESC); + put_char(b'['); + put_char(b'C'); + } else { + put_char(BEL); + } + } + direction @ b'A' | direction @ b'B' => { + if direction == b'A' && history_index > 0 { + // Up arrow + history_index -= 1; + } else if direction == b'B' && history.len() > 0 // usize underflow + && history_index < history.len() - 1 + { + // Down arrow + history_index += 1; + } else { + put_char(BEL); + continue; + } + + for _ in 0..line_vec.len() { + put_char(ESC); + put_char(b'['); + put_char(b'D'); + } + for _ in 0..line_vec.len() { + put_char(b' '); + } + for _ in 0..line_vec.len() { + put_char(ESC); + put_char(b'['); + put_char(b'D'); + } + line_vec = history[history_index].clone(); + cursor = line_vec.len(); + for byte in &line_vec { + put_char(*byte); + } + } + _ => { + put_char(BEL); + } + } + } + _ => { + put_char(BEL); + } + } + } + byte if byte.is_ascii_graphic() || byte == b' ' => { + line_vec.insert(cursor, byte); + for byte in &line_vec[cursor..] { + put_char(*byte); + } + cursor += 1; + for _i in cursor..line_vec.len() { + put_char(BS); + } + } + _ => { + // unrecognized characters + put_char(BEL); } - _ => {} } } + + history.push(line_vec.clone()); + String::from_utf8(line_vec).unwrap_or_default() +} + +fn get_char() -> u8 { + crate::fs::STDIN.pop() as u8 } -fn get_char() -> char { - crate::fs::STDIN.pop() +fn put_char(ch: u8) { + print!("{}", ch as char); } diff --git a/kernel/src/syscall/net.rs b/kernel/src/syscall/net.rs index 6bbe6d6..88e0c59 100644 --- a/kernel/src/syscall/net.rs +++ b/kernel/src/syscall/net.rs @@ -82,6 +82,18 @@ struct SockaddrIn { sin_zero: [u8; 8], } +fn get_handle(proc: &mut MutexGuard<'static, Process>, fd: usize) -> Result { + if let Some(file) = proc.files.get(&fd) { + if let FileLike::Socket(handle) = file { + return Ok((*handle).clone()); + } else { + Err(SysError::ENOTSOCK) + } + } else { + Err(SysError::EBADF) + } +} + pub fn sys_connect(fd: usize, addr: *const u8, addrlen: usize) -> SysResult { info!( "sys_connect: fd: {}, addr: {:?}, addrlen: {}", @@ -110,28 +122,24 @@ pub fn sys_connect(fd: usize, addr: *const u8, addrlen: usize) -> SysResult { let iface = &mut *NET_DRIVERS.lock()[0]; iface.poll(&mut proc.sockets); - if let Some(FileLike::Socket(handle)) = proc.files.get(&fd) { - // TODO: check its type - let tcp_handle = (*handle).clone(); - let mut socket = proc.sockets.get::(tcp_handle); - - // TODO selects non-conflict high port - static mut ephermeral_port: u16 = 49152; - let temp_port = unsafe { - if ephermeral_port == 65535 { - ephermeral_port = 49152; - } else { - ephermeral_port = ephermeral_port + 1; - } - ephermeral_port - }; + // TODO: check its type + let tcp_handle = get_handle(&mut proc, fd)?; + let mut socket = proc.sockets.get::(tcp_handle); - match socket.connect((dest.unwrap(), port), temp_port) { - Ok(()) => Ok(0), - Err(_) => Err(SysError::EISCONN), + // TODO selects non-conflict high port + static mut ephermeral_port: u16 = 49152; + let temp_port = unsafe { + if ephermeral_port == 65535 { + ephermeral_port = 49152; + } else { + ephermeral_port = ephermeral_port + 1; } - } else { - Err(SysError::ENOTSOCK) + ephermeral_port + }; + + match socket.connect((dest.unwrap(), port), temp_port) { + Ok(()) => Ok(0), + Err(_) => Err(SysError::EISCONN), } } @@ -145,25 +153,21 @@ pub fn sys_write_socket( let iface = &mut *NET_DRIVERS.lock()[0]; iface.poll(&mut proc.sockets); - if let Some(FileLike::Socket(handle)) = proc.files.get(&fd) { - // TODO: check its type - let tcp_handle = (*handle).clone(); - let mut socket = proc.sockets.get::(tcp_handle); - let slice = unsafe { slice::from_raw_parts(base, len) }; - if socket.is_open() { - if socket.can_send() { - match socket.send_slice(&slice) { - Ok(size) => Ok(size as isize), - Err(err) => Err(SysError::ENOBUFS) - } - } else { - Err(SysError::ENOBUFS) + // TODO: check its type + let tcp_handle = get_handle(proc, fd)?; + let mut socket = proc.sockets.get::(tcp_handle); + let slice = unsafe { slice::from_raw_parts(base, len) }; + if socket.is_open() { + if socket.can_send() { + match socket.send_slice(&slice) { + Ok(size) => Ok(size as isize), + Err(err) => Err(SysError::ENOBUFS) } } else { - Err(SysError::ECONNREFUSED) + Err(SysError::ENOBUFS) } } else { - Err(SysError::ENOTSOCK) + Err(SysError::ECONNREFUSED) } }