#![no_std]
#![no_main]
#![allow(clippy::println_empty_string)]

extern crate alloc;

const LF: u8 = 0x0au8;
const CR: u8 = 0x0du8;
const DL: u8 = 0x7fu8;
const BS: u8 = 0x08u8;

use alloc::string::String;
use user_lib::{ print, println, waitpid};
use user_lib::syscall::{sys_exec, sys_yield, sys_fork, sys_get_time};
use user_lib::user_console::getchar;


#[no_mangle]
pub fn main() -> i32 {
    println!("Rust user shell");

    // line变量 维护着当前输入的内容, 它不断发生变化
    let mut line: String = String::new();
    print!(">> ");
    loop {
        // 循环读取标准输入
        let c = getchar();

        match c {
            // 如果是 回车键, 开启一个新的进程, 把 line中的内容 使用exec 执行
            LF | CR => {
                println!("");
                if !line.is_empty() {
                    line.push('\0');
                    let mut st = sys_get_time();

                    let pid = sys_fork();
                    if pid == 0 {
                        // child process
                        if sys_exec(line.as_str()) == -1 {
                            // 返回 -1 说明没有存在 line中的程序
                            println!("Error when executing!");
                            return -4;
                        }
                        unreachable!();
                    } else {
                        // 等待上方子进程结束
                        let mut exit_code: i32 = 0;
                        let exit_pid = waitpid(pid as usize, &mut exit_code);
                        assert_eq!(pid, exit_pid);
                        println!("Shell: Process {} exited with code {}, use time: {}ms", pid, exit_code, sys_get_time()-st);
                    }
                    line.clear();
                }
                print!(">> ");
            }
            // 如果是退格键
            BS | DL => {
                if !line.is_empty() {
                    print!("{}", BS as char);
                    print!(" ");
                    print!("{}", BS as char);
                    line.pop();
                }
            }
            _ => {
                print!("{}", c as char);
                line.push(c as char);
            }
        }
    }
}
