Add line editing function to user shell and refactor net syscall

master
Jiajie Chen 6 years ago
parent 6124cd60fc
commit 29865d7aaa

@ -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<Vec<u8>>) -> 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);
}
}
CR | LF => {
// Return
put_char(CR);
put_char(LF);
break;
}
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);
}
}
}
' '...'\u{7e}' => {
s.push(c);
print!("{}", c);
_ => {
put_char(BEL);
}
'\n' | '\r' => {
print!("\n");
return s;
}
_ => {}
}
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);
}

@ -82,6 +82,18 @@ struct SockaddrIn {
sin_zero: [u8; 8],
}
fn get_handle(proc: &mut MutexGuard<'static, Process>, fd: usize) -> Result<SocketHandle, SysError> {
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,9 +122,8 @@ 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 tcp_handle = get_handle(&mut proc, fd)?;
let mut socket = proc.sockets.get::<TcpSocket>(tcp_handle);
// TODO selects non-conflict high port
@ -130,9 +141,6 @@ pub fn sys_connect(fd: usize, addr: *const u8, addrlen: usize) -> SysResult {
Ok(()) => Ok(0),
Err(_) => Err(SysError::EISCONN),
}
} else {
Err(SysError::ENOTSOCK)
}
}
pub fn sys_write_socket(
@ -145,9 +153,8 @@ 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 tcp_handle = get_handle(proc, fd)?;
let mut socket = proc.sockets.get::<TcpSocket>(tcp_handle);
let slice = unsafe { slice::from_raw_parts(base, len) };
if socket.is_open() {
@ -162,9 +169,6 @@ pub fn sys_write_socket(
} else {
Err(SysError::ECONNREFUSED)
}
} else {
Err(SysError::ENOTSOCK)
}
}
pub fn sys_select(

Loading…
Cancel
Save