|
@@ -0,0 +1,2016 @@
|
|
|
|
+use core::ops::BitXor;
|
|
|
|
+
|
|
|
|
+use bitmap::{traits::BitMapOps, StaticBitmap};
|
|
|
|
+
|
|
|
|
+use alloc::sync::{Arc, Weak};
|
|
|
|
+use system_error::SystemError;
|
|
|
|
+
|
|
|
|
+use crate::{
|
|
|
|
+ arch::ipc::signal::Signal,
|
|
|
|
+ driver::tty::{
|
|
|
|
+ termios::{ControlCharIndex, InputMode, LocalMode, OutputMode, Termios},
|
|
|
|
+ tty_core::{EchoOperation, TtyCore, TtyCoreData, TtyFlag, TtyIoctlCmd},
|
|
|
|
+ tty_driver::{TtyDriverFlag, TtyOperation},
|
|
|
|
+ tty_job_control::TtyJobCtrlManager,
|
|
|
|
+ },
|
|
|
|
+ filesystem::vfs::file::FileMode,
|
|
|
|
+ libs::{
|
|
|
|
+ rwlock::RwLockReadGuard,
|
|
|
|
+ spinlock::{SpinLock, SpinLockGuard},
|
|
|
|
+ },
|
|
|
|
+ mm::VirtAddr,
|
|
|
|
+ net::event_poll::EPollEventType,
|
|
|
|
+ process::ProcessManager,
|
|
|
|
+ syscall::{user_access::UserBufferWriter, Syscall},
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+use super::TtyLineDiscipline;
|
|
|
|
+pub const NTTY_BUFSIZE: usize = 4096;
|
|
|
|
+pub const ECHO_COMMIT_WATERMARK: usize = 256;
|
|
|
|
+pub const ECHO_BLOCK: usize = 256;
|
|
|
|
+pub const ECHO_DISCARD_WATERMARK: usize = NTTY_BUFSIZE - (ECHO_BLOCK + 32);
|
|
|
|
+
|
|
|
|
+fn ntty_buf_mask(idx: usize) -> usize {
|
|
|
|
+ return idx & (NTTY_BUFSIZE - 1);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+#[derive(Debug)]
|
|
|
|
+pub struct NTtyLinediscipline {
|
|
|
|
+ pub data: SpinLock<NTtyData>,
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+impl NTtyLinediscipline {
|
|
|
|
+ #[inline]
|
|
|
|
+ pub fn disc_data(&self) -> SpinLockGuard<NTtyData> {
|
|
|
|
+ self.data.lock_irqsave()
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ #[inline]
|
|
|
|
+ pub fn disc_data_try_lock(&self) -> Result<SpinLockGuard<NTtyData>, SystemError> {
|
|
|
|
+ self.data.try_lock_irqsave()
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ fn ioctl_helper(&self, tty: Arc<TtyCore>, cmd: u32, arg: usize) -> Result<usize, SystemError> {
|
|
|
|
+ match cmd {
|
|
|
|
+ TtyIoctlCmd::TCXONC => {
|
|
|
|
+ todo!()
|
|
|
|
+ }
|
|
|
|
+ TtyIoctlCmd::TCFLSH => {
|
|
|
|
+ todo!()
|
|
|
|
+ }
|
|
|
|
+ _ => {
|
|
|
|
+ return tty.tty_mode_ioctl(tty.clone(), cmd, arg);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+#[derive(Debug)]
|
|
|
|
+pub struct NTtyData {
|
|
|
|
+ /// 写者管理,tty只有一个写者,即ttydevice,所以不需要加锁
|
|
|
|
+ /// 读取缓冲区的头指针,表示下一个将要接受进buf的字符的位置
|
|
|
|
+ read_head: usize,
|
|
|
|
+ /// 提交缓冲区的头指针,用于行规程处理
|
|
|
|
+ commit_head: usize,
|
|
|
|
+ /// 规范缓冲区的头指针,用于规范模式的处理
|
|
|
|
+ canon_head: usize,
|
|
|
|
+ /// 回显缓冲区的头指针,用于存储需要回显的字符
|
|
|
|
+ echo_head: usize,
|
|
|
|
+ /// 回显过程中用于提交的头指针
|
|
|
|
+ echo_commit: usize,
|
|
|
|
+ /// 标记回显字符的起始位置
|
|
|
|
+ echo_mark: usize,
|
|
|
|
+
|
|
|
|
+ /// 读者管理
|
|
|
|
+ /// 读取字符的尾指针,即当前读取位置
|
|
|
|
+ read_tail: usize,
|
|
|
|
+ /// 行的起始位置
|
|
|
|
+ line_start: usize,
|
|
|
|
+ /// 预读字符数,用于处理控制字符
|
|
|
|
+ lookahead_count: usize,
|
|
|
|
+
|
|
|
|
+ // 更改以下六个标记时必须持有termios的锁
|
|
|
|
+ /// Line-next 标志,表示下一个输入字符应当按字面处理
|
|
|
|
+ lnext: bool,
|
|
|
|
+ /// 擦除状态的标志
|
|
|
|
+ erasing: bool,
|
|
|
|
+ /// Raw 模式的标志
|
|
|
|
+ raw: bool,
|
|
|
|
+ /// Real raw 模式的标志
|
|
|
|
+ real_raw: bool,
|
|
|
|
+ /// 规范模式的标志
|
|
|
|
+ icanon: bool,
|
|
|
|
+ /// 是否开启echo
|
|
|
|
+ echo: bool,
|
|
|
|
+ /// 标志是否正在进行推送
|
|
|
|
+ pushing: bool,
|
|
|
|
+ /// 是否没有空间可写
|
|
|
|
+ no_room: bool,
|
|
|
|
+
|
|
|
|
+ /// 光标所在列
|
|
|
|
+ cursor_column: u32,
|
|
|
|
+ /// 规范模式下光标所在列
|
|
|
|
+ canon_cursor_column: u32,
|
|
|
|
+ /// 回显缓冲区的尾指针
|
|
|
|
+ echo_tail: usize,
|
|
|
|
+
|
|
|
|
+ /// 写者与读者共享
|
|
|
|
+ read_buf: [u8; NTTY_BUFSIZE],
|
|
|
|
+ echo_buf: [u8; NTTY_BUFSIZE],
|
|
|
|
+
|
|
|
|
+ read_flags: StaticBitmap<NTTY_BUFSIZE>,
|
|
|
|
+ char_map: StaticBitmap<256>,
|
|
|
|
+
|
|
|
|
+ tty: Option<Weak<TtyCore>>,
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+impl NTtyData {
|
|
|
|
+ pub fn new() -> Self {
|
|
|
|
+ Self {
|
|
|
|
+ read_head: 0,
|
|
|
|
+ commit_head: 0,
|
|
|
|
+ canon_head: 0,
|
|
|
|
+ echo_head: 0,
|
|
|
|
+ echo_commit: 0,
|
|
|
|
+ echo_mark: 0,
|
|
|
|
+ read_tail: 0,
|
|
|
|
+ line_start: 0,
|
|
|
|
+ lookahead_count: 0,
|
|
|
|
+ lnext: false,
|
|
|
|
+ erasing: false,
|
|
|
|
+ raw: false,
|
|
|
|
+ real_raw: false,
|
|
|
|
+ icanon: false,
|
|
|
|
+ pushing: false,
|
|
|
|
+ echo: false,
|
|
|
|
+ cursor_column: 0,
|
|
|
|
+ canon_cursor_column: 0,
|
|
|
|
+ echo_tail: 0,
|
|
|
|
+ read_buf: [0; NTTY_BUFSIZE],
|
|
|
|
+ echo_buf: [0; NTTY_BUFSIZE],
|
|
|
|
+ read_flags: StaticBitmap::new(),
|
|
|
|
+ char_map: StaticBitmap::new(),
|
|
|
|
+ tty: None,
|
|
|
|
+ no_room: false,
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ #[inline]
|
|
|
|
+ pub fn read_cnt(&self) -> usize {
|
|
|
|
+ self.read_head - self.read_tail
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ #[inline]
|
|
|
|
+ pub fn read_at(&self, i: usize) -> u8 {
|
|
|
|
+ let i = i & (NTTY_BUFSIZE - 1);
|
|
|
|
+ self.read_buf[i]
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /// ### 接收数据到NTTY
|
|
|
|
+ pub fn receive_buf_common(
|
|
|
|
+ &mut self,
|
|
|
|
+ tty: Arc<TtyCore>,
|
|
|
|
+ buf: &[u8],
|
|
|
|
+ flags: Option<&[u8]>,
|
|
|
|
+ mut count: usize,
|
|
|
|
+ flow: bool,
|
|
|
|
+ ) -> Result<usize, SystemError> {
|
|
|
|
+ // 获取termios读锁
|
|
|
|
+ let termios = tty.core().termios();
|
|
|
|
+ let mut overflow;
|
|
|
|
+ let mut n;
|
|
|
|
+ let mut offset = 0;
|
|
|
|
+ let mut recved = 0;
|
|
|
|
+ loop {
|
|
|
|
+ let tail = self.read_tail;
|
|
|
|
+
|
|
|
|
+ let mut room = NTTY_BUFSIZE - (self.read_head - tail);
|
|
|
|
+ if termios.input_mode.contains(InputMode::PARMRK) {
|
|
|
|
+ room = (room + 2) / 3;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ room -= 1;
|
|
|
|
+ if room == 0 || room > NTTY_BUFSIZE {
|
|
|
|
+ // 可能溢出
|
|
|
|
+ overflow = self.icanon && self.canon_head == tail;
|
|
|
|
+ if room > NTTY_BUFSIZE && overflow {
|
|
|
|
+ self.read_head -= 1;
|
|
|
|
+ }
|
|
|
|
+ self.no_room = flow && !overflow;
|
|
|
|
+ room = if overflow { !0 } else { 0 }
|
|
|
|
+ } else {
|
|
|
|
+ overflow = false;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ n = count.min(room);
|
|
|
|
+ if n == 0 {
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if !overflow {
|
|
|
|
+ if flags.is_none() {
|
|
|
|
+ self.receive_buf(tty.clone(), &buf[offset..], flags, n);
|
|
|
|
+ } else {
|
|
|
|
+ self.receive_buf(
|
|
|
|
+ tty.clone(),
|
|
|
|
+ &buf[offset..],
|
|
|
|
+ Some(&flags.unwrap()[offset..]),
|
|
|
|
+ n,
|
|
|
|
+ );
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ offset += n;
|
|
|
|
+
|
|
|
|
+ count -= n;
|
|
|
|
+
|
|
|
|
+ recved += n;
|
|
|
|
+
|
|
|
|
+ if tty.core().flags().contains(TtyFlag::LDISC_CHANGING) {
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // TODO: throttle
|
|
|
|
+
|
|
|
|
+ Ok(recved)
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ pub fn receive_buf(
|
|
|
|
+ &mut self,
|
|
|
|
+ tty: Arc<TtyCore>,
|
|
|
|
+ buf: &[u8],
|
|
|
|
+ flags: Option<&[u8]>,
|
|
|
|
+ count: usize,
|
|
|
|
+ ) {
|
|
|
|
+ let termios = tty.core().termios();
|
|
|
|
+ let preops = termios.input_mode.contains(InputMode::ISTRIP)
|
|
|
|
+ || termios.input_mode.contains(InputMode::IUCLC)
|
|
|
|
+ || termios.local_mode.contains(LocalMode::IEXTEN);
|
|
|
|
+
|
|
|
|
+ let look_ahead = self.lookahead_count.min(count);
|
|
|
|
+
|
|
|
|
+ if self.real_raw {
|
|
|
|
+ todo!("tty real raw mode todo");
|
|
|
|
+ } else if self.raw || (termios.local_mode.contains(LocalMode::EXTPROC) && !preops) {
|
|
|
|
+ todo!("tty raw mode todo");
|
|
|
|
+ } else if tty.core().is_closing() && !termios.local_mode.contains(LocalMode::EXTPROC) {
|
|
|
|
+ todo!()
|
|
|
|
+ } else {
|
|
|
|
+ if look_ahead > 0 {
|
|
|
|
+ self.receive_buf_standard(tty.clone(), buf, flags, look_ahead, true);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if count > look_ahead {
|
|
|
|
+ self.receive_buf_standard(tty.clone(), buf, flags, count - look_ahead, false);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 刷新echo
|
|
|
|
+ self.flush_echoes(tty.clone());
|
|
|
|
+
|
|
|
|
+ tty.flush_chars(tty.core());
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ self.lookahead_count -= look_ahead;
|
|
|
|
+
|
|
|
|
+ if self.icanon && !termios.local_mode.contains(LocalMode::EXTPROC) {
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ self.commit_head = self.read_head;
|
|
|
|
+
|
|
|
|
+ if self.read_cnt() > 0 {
|
|
|
|
+ tty.core()
|
|
|
|
+ .read_wq()
|
|
|
|
+ .wakeup((EPollEventType::EPOLLIN | EPollEventType::EPOLLRDBAND).bits() as u64);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ pub fn flush_echoes(&mut self, tty: Arc<TtyCore>) {
|
|
|
|
+ let termios = tty.core().termios();
|
|
|
|
+ if !termios.local_mode.contains(LocalMode::ECHO)
|
|
|
|
+ && !termios.local_mode.contains(LocalMode::ECHONL)
|
|
|
|
+ || self.echo_commit == self.echo_head
|
|
|
|
+ {
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ self.echo_commit = self.echo_head;
|
|
|
|
+ drop(termios);
|
|
|
|
+ let _ = self.echoes(tty);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ pub fn receive_buf_standard(
|
|
|
|
+ &mut self,
|
|
|
|
+ tty: Arc<TtyCore>,
|
|
|
|
+ buf: &[u8],
|
|
|
|
+ flags: Option<&[u8]>,
|
|
|
|
+ mut count: usize,
|
|
|
|
+ lookahead_done: bool,
|
|
|
|
+ ) {
|
|
|
|
+ let termios = tty.core().termios();
|
|
|
|
+ if flags.is_some() {
|
|
|
|
+ todo!("ntty recv buf flags todo");
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ let mut offset = 0;
|
|
|
|
+ while count > 0 {
|
|
|
|
+ if offset >= buf.len() {
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ let mut c = buf[offset];
|
|
|
|
+ offset += 1;
|
|
|
|
+
|
|
|
|
+ if self.lnext {
|
|
|
|
+ // 将下一个字符当做字面值处理
|
|
|
|
+ self.lnext = false;
|
|
|
|
+ if termios.input_mode.contains(InputMode::ISTRIP) {
|
|
|
|
+ c &= 0x7f;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if termios.input_mode.contains(InputMode::IUCLC)
|
|
|
|
+ && termios.local_mode.contains(LocalMode::IEXTEN)
|
|
|
|
+ {
|
|
|
|
+ c = (c as char).to_ascii_lowercase() as u8;
|
|
|
|
+ self.receive_char(c, tty.clone())
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if termios.input_mode.contains(InputMode::ISTRIP) {
|
|
|
|
+ c &= 0x7f;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if termios.input_mode.contains(InputMode::IUCLC)
|
|
|
|
+ && termios.local_mode.contains(LocalMode::IEXTEN)
|
|
|
|
+ {
|
|
|
|
+ c = (c as char).to_ascii_lowercase() as u8;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if termios.local_mode.contains(LocalMode::EXTPROC) {
|
|
|
|
+ self.add_read_byte(c);
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if self.char_map.get(c as usize).unwrap() {
|
|
|
|
+ // 特殊字符
|
|
|
|
+ self.receive_special_char(c, tty.clone(), lookahead_done)
|
|
|
|
+ } else {
|
|
|
|
+ self.receive_char(c, tty.clone());
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ count -= 1;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ pub fn receive_special_char(&mut self, mut c: u8, tty: Arc<TtyCore>, lookahead_done: bool) {
|
|
|
|
+ let is_flow_ctrl = self.is_flow_ctrl_char(tty.clone(), c, lookahead_done);
|
|
|
|
+ let termios = tty.core().termios();
|
|
|
|
+
|
|
|
|
+ // 启用软件流控,并且该字符已经当做软件流控字符处理
|
|
|
|
+ if termios.input_mode.contains(InputMode::IXON) && is_flow_ctrl {
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if termios.local_mode.contains(LocalMode::ISIG) {
|
|
|
|
+ if c == termios.control_characters[ControlCharIndex::VINTR] {
|
|
|
|
+ self.recv_sig_char(tty.clone(), &termios, Signal::SIGINT, c);
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if c == termios.control_characters[ControlCharIndex::VQUIT] {
|
|
|
|
+ self.recv_sig_char(tty.clone(), &termios, Signal::SIGQUIT, c);
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if c == termios.control_characters[ControlCharIndex::VSUSP] {
|
|
|
|
+ self.recv_sig_char(tty.clone(), &termios, Signal::SIGTSTP, c);
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ let flow = tty.core().flow_irqsave();
|
|
|
|
+ if flow.stopped
|
|
|
|
+ && !flow.tco_stopped
|
|
|
|
+ && termios.input_mode.contains(InputMode::IXON)
|
|
|
|
+ && termios.input_mode.contains(InputMode::IXANY)
|
|
|
|
+ {
|
|
|
|
+ tty.tty_start();
|
|
|
|
+ self.process_echoes(tty.clone());
|
|
|
|
+ }
|
|
|
|
+ drop(flow);
|
|
|
|
+
|
|
|
|
+ if c == b'\r' {
|
|
|
|
+ if termios.input_mode.contains(InputMode::IGNCR) {
|
|
|
|
+ // 忽略
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ if termios.input_mode.contains(InputMode::ICRNL) {
|
|
|
|
+ // 映射为换行
|
|
|
|
+ c = b'\n';
|
|
|
|
+ }
|
|
|
|
+ } else if c == b'\n' && termios.input_mode.contains(InputMode::INLCR) {
|
|
|
|
+ // 映射为回车
|
|
|
|
+ c = b'\r';
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if self.icanon {
|
|
|
|
+ if c == termios.control_characters[ControlCharIndex::VERASE]
|
|
|
|
+ || c == termios.control_characters[ControlCharIndex::VKILL]
|
|
|
|
+ || (c == termios.control_characters[ControlCharIndex::VWERASE]
|
|
|
|
+ && termios.local_mode.contains(LocalMode::IEXTEN))
|
|
|
|
+ {
|
|
|
|
+ self.eraser(c, &termios);
|
|
|
|
+ self.commit_echoes(tty.clone());
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ if c == termios.control_characters[ControlCharIndex::VLNEXT]
|
|
|
|
+ && termios.local_mode.contains(LocalMode::IEXTEN)
|
|
|
|
+ {
|
|
|
|
+ self.lnext = true;
|
|
|
|
+ if termios.local_mode.contains(LocalMode::ECHO) {
|
|
|
|
+ self.finish_erasing();
|
|
|
|
+ if termios.local_mode.contains(LocalMode::ECHOCTL) {
|
|
|
|
+ self.echo_char_raw(b'^');
|
|
|
|
+ self.echo_char_raw(8);
|
|
|
|
+ self.commit_echoes(tty.clone());
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ if c == termios.control_characters[ControlCharIndex::VREPRINT]
|
|
|
|
+ && termios.local_mode.contains(LocalMode::ECHO)
|
|
|
|
+ && termios.local_mode.contains(LocalMode::IEXTEN)
|
|
|
|
+ {
|
|
|
|
+ let mut tail = self.canon_head;
|
|
|
|
+ self.finish_erasing();
|
|
|
|
+ self.echo_char(c, &termios);
|
|
|
|
+ self.echo_char_raw(b'\n');
|
|
|
|
+ while ntty_buf_mask(tail) != ntty_buf_mask(self.read_head) {
|
|
|
|
+ self.echo_char(self.read_buf[ntty_buf_mask(tail)], &termios);
|
|
|
|
+ tail += 1;
|
|
|
|
+ }
|
|
|
|
+ self.commit_echoes(tty.clone());
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if c == b'\n' {
|
|
|
|
+ if termios.local_mode.contains(LocalMode::ECHO)
|
|
|
|
+ || termios.local_mode.contains(LocalMode::ECHONL)
|
|
|
|
+ {
|
|
|
|
+ self.echo_char_raw(b'\n');
|
|
|
|
+ self.commit_echoes(tty.clone());
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ self.read_flags.set(ntty_buf_mask(self.read_head), true);
|
|
|
|
+ self.read_buf[ntty_buf_mask(self.read_head)] = c;
|
|
|
|
+ self.read_head += 1;
|
|
|
|
+ self.canon_head = self.read_head;
|
|
|
|
+ tty.core()
|
|
|
|
+ .read_wq()
|
|
|
|
+ .wakeup((EPollEventType::EPOLLIN | EPollEventType::EPOLLRDNORM).bits() as u64);
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if c == termios.control_characters[ControlCharIndex::VEOF] {
|
|
|
|
+ c = ControlCharIndex::DISABLE_CHAR;
|
|
|
|
+
|
|
|
|
+ self.read_flags.set(ntty_buf_mask(self.read_head), true);
|
|
|
|
+ self.read_buf[ntty_buf_mask(self.read_head)] = c;
|
|
|
|
+ self.read_head += 1;
|
|
|
|
+ self.canon_head = self.read_head;
|
|
|
|
+ tty.core()
|
|
|
|
+ .read_wq()
|
|
|
|
+ .wakeup((EPollEventType::EPOLLIN | EPollEventType::EPOLLRDNORM).bits() as u64);
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if c == termios.control_characters[ControlCharIndex::VEOL]
|
|
|
|
+ || (c == termios.control_characters[ControlCharIndex::VEOL2]
|
|
|
|
+ && termios.local_mode.contains(LocalMode::IEXTEN))
|
|
|
|
+ {
|
|
|
|
+ if termios.local_mode.contains(LocalMode::ECHO) {
|
|
|
|
+ if self.canon_head == self.read_head {
|
|
|
|
+ self.add_echo_byte(EchoOperation::Start.to_u8());
|
|
|
|
+ self.add_echo_byte(EchoOperation::SetCanonCol.to_u8());
|
|
|
|
+ }
|
|
|
|
+ self.echo_char(c, &termios);
|
|
|
|
+ self.commit_echoes(tty.clone());
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if c == 0o377 && termios.input_mode.contains(InputMode::PARMRK) {
|
|
|
|
+ self.read_buf[ntty_buf_mask(self.read_head)] = c;
|
|
|
|
+ self.read_head += 1;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ self.read_flags.set(ntty_buf_mask(self.read_head), true);
|
|
|
|
+ self.read_buf[ntty_buf_mask(self.read_head)] = c;
|
|
|
|
+ self.read_head += 1;
|
|
|
|
+ self.canon_head = self.read_head;
|
|
|
|
+ tty.core()
|
|
|
|
+ .read_wq()
|
|
|
|
+ .wakeup((EPollEventType::EPOLLIN | EPollEventType::EPOLLRDNORM).bits() as u64);
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if termios.local_mode.contains(LocalMode::ECHO) {
|
|
|
|
+ self.finish_erasing();
|
|
|
|
+ if c == b'\n' {
|
|
|
|
+ self.echo_char_raw(b'\n');
|
|
|
|
+ } else {
|
|
|
|
+ if self.canon_head == self.read_head {
|
|
|
|
+ self.add_echo_byte(EchoOperation::Start.to_u8());
|
|
|
|
+ self.add_echo_byte(EchoOperation::SetCanonCol.to_u8());
|
|
|
|
+ }
|
|
|
|
+ self.echo_char(c, &termios);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ self.commit_echoes(tty.clone());
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if c == 0o377 && termios.input_mode.contains(InputMode::PARMRK) {
|
|
|
|
+ self.read_buf[ntty_buf_mask(self.read_head)] = c;
|
|
|
|
+ self.read_head += 1;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ self.read_buf[ntty_buf_mask(self.read_head)] = c;
|
|
|
|
+ self.read_head += 1;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /// ## ntty默认eraser function
|
|
|
|
+ fn eraser(&mut self, mut c: u8, termios: &RwLockReadGuard<Termios>) {
|
|
|
|
+ if self.read_head == self.canon_head {
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ let erase = c == termios.control_characters[ControlCharIndex::VERASE];
|
|
|
|
+ let werase = c == termios.control_characters[ControlCharIndex::VWERASE];
|
|
|
|
+ let kill = !erase && !werase;
|
|
|
|
+
|
|
|
|
+ if kill {
|
|
|
|
+ if !termios.local_mode.contains(LocalMode::ECHO) {
|
|
|
|
+ self.read_head = self.canon_head;
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ if !termios.local_mode.contains(LocalMode::ECHOK)
|
|
|
|
+ || !termios.local_mode.contains(LocalMode::ECHOKE)
|
|
|
|
+ || !termios.local_mode.contains(LocalMode::ECHOE)
|
|
|
|
+ {
|
|
|
|
+ self.read_head = self.canon_head;
|
|
|
|
+ if self.erasing {
|
|
|
|
+ self.echo_char_raw(c);
|
|
|
|
+ self.erasing = false;
|
|
|
|
+ }
|
|
|
|
+ self.echo_char(c, termios);
|
|
|
|
+
|
|
|
|
+ if termios.local_mode.contains(LocalMode::ECHOK) {
|
|
|
|
+ // 添加新行
|
|
|
|
+ self.echo_char_raw(b'\n');
|
|
|
|
+ }
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ let mut head;
|
|
|
|
+ let mut cnt;
|
|
|
|
+ while ntty_buf_mask(self.read_head) != ntty_buf_mask(self.canon_head) {
|
|
|
|
+ head = self.read_head;
|
|
|
|
+
|
|
|
|
+ loop {
|
|
|
|
+ // 消除多字节字符
|
|
|
|
+ head -= 1;
|
|
|
|
+ c = self.read_buf[ntty_buf_mask(head)];
|
|
|
|
+
|
|
|
|
+ if !(Self::is_continuation(c, termios)
|
|
|
|
+ && ntty_buf_mask(head) != ntty_buf_mask(self.canon_head))
|
|
|
|
+ {
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if Self::is_continuation(c, termios) {
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if werase {
|
|
|
|
+ todo!()
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ cnt = self.read_head - head;
|
|
|
|
+ self.read_head = head;
|
|
|
|
+ if termios.local_mode.contains(LocalMode::ECHO) {
|
|
|
|
+ if termios.local_mode.contains(LocalMode::ECHOPRT) {
|
|
|
|
+ if !self.erasing {
|
|
|
|
+ self.echo_char_raw(b'\\');
|
|
|
|
+ self.erasing = true;
|
|
|
|
+ }
|
|
|
|
+ self.echo_char(c, termios);
|
|
|
|
+ cnt -= 1;
|
|
|
|
+ while cnt > 0 {
|
|
|
|
+ cnt -= 1;
|
|
|
|
+ head += 1;
|
|
|
|
+ self.echo_char_raw(self.read_buf[ntty_buf_mask(head)]);
|
|
|
|
+ self.add_echo_byte(EchoOperation::Start.to_u8());
|
|
|
|
+ self.add_echo_byte(EchoOperation::MoveBackCol.to_u8());
|
|
|
|
+ }
|
|
|
|
+ } else if erase && !termios.local_mode.contains(LocalMode::ECHOE) {
|
|
|
|
+ self.echo_char(
|
|
|
|
+ termios.control_characters[ControlCharIndex::VERASE],
|
|
|
|
+ termios,
|
|
|
|
+ );
|
|
|
|
+ } else if c == b'\t' {
|
|
|
|
+ let mut num_chars = 0;
|
|
|
|
+ let mut after_tab = false;
|
|
|
|
+ let mut tail = self.read_head;
|
|
|
|
+
|
|
|
|
+ while ntty_buf_mask(tail) != ntty_buf_mask(self.canon_head) {
|
|
|
|
+ tail -= 1;
|
|
|
|
+ c = self.read_buf[ntty_buf_mask(tail)];
|
|
|
|
+ if c == b'\t' {
|
|
|
|
+ after_tab = true;
|
|
|
|
+ break;
|
|
|
|
+ } else if (c as char).is_control() {
|
|
|
|
+ if termios.local_mode.contains(LocalMode::ECHOCTL) {
|
|
|
|
+ num_chars += 2;
|
|
|
|
+ }
|
|
|
|
+ } else if !Self::is_continuation(c, termios) {
|
|
|
|
+ num_chars += 1;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ self.echo_erase_tab(num_chars, after_tab);
|
|
|
|
+ } else {
|
|
|
|
+ if (c as char).is_control() && termios.local_mode.contains(LocalMode::ECHOCTL) {
|
|
|
|
+ // 8 => '\b'
|
|
|
|
+ self.echo_char_raw(8);
|
|
|
|
+ self.echo_char_raw(b' ');
|
|
|
|
+ self.echo_char_raw(8);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if !(c as char).is_control() || termios.local_mode.contains(LocalMode::ECHOCTL)
|
|
|
|
+ {
|
|
|
|
+ // 8 => '\b'
|
|
|
|
+ self.echo_char_raw(8);
|
|
|
|
+ self.echo_char_raw(b' ');
|
|
|
|
+ self.echo_char_raw(8);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if erase {
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if self.read_head == self.canon_head && termios.local_mode.contains(LocalMode::ECHO) {
|
|
|
|
+ self.finish_erasing();
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ fn finish_erasing(&mut self) {
|
|
|
|
+ if self.erasing {
|
|
|
|
+ self.echo_char_raw(b'/');
|
|
|
|
+ self.erasing = false;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ fn echo_erase_tab(&mut self, mut num: u8, after_tab: bool) {
|
|
|
|
+ self.add_echo_byte(EchoOperation::Start.to_u8());
|
|
|
|
+ self.add_echo_byte(EchoOperation::EraseTab.to_u8());
|
|
|
|
+
|
|
|
|
+ num &= 7;
|
|
|
|
+
|
|
|
|
+ if after_tab {
|
|
|
|
+ num |= 0x80;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ self.add_echo_byte(num);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /// ## 多字节字符检测
|
|
|
|
+ /// 检测是否为多字节字符的后续字节
|
|
|
|
+ fn is_continuation(c: u8, termios: &RwLockReadGuard<Termios>) -> bool {
|
|
|
|
+ return termios.input_mode.contains(InputMode::IUTF8) && (c & 0xc0) == 0x80;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /// ## 该字符是否已经当做流控字符处理
|
|
|
|
+ pub fn is_flow_ctrl_char(&mut self, tty: Arc<TtyCore>, c: u8, lookahead_done: bool) -> bool {
|
|
|
|
+ let termios = tty.core().termios();
|
|
|
|
+
|
|
|
|
+ if !(termios.control_characters[ControlCharIndex::VSTART] == c
|
|
|
|
+ || termios.control_characters[ControlCharIndex::VSTOP] == c)
|
|
|
|
+ {
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if lookahead_done {
|
|
|
|
+ return true;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if termios.control_characters[ControlCharIndex::VSTART] == c {
|
|
|
|
+ tty.tty_start();
|
|
|
|
+ self.process_echoes(tty.clone());
|
|
|
|
+ return true;
|
|
|
|
+ } else {
|
|
|
|
+ tty.tty_stop();
|
|
|
|
+ return true;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /// ## 接收到信号字符时的处理
|
|
|
|
+ fn recv_sig_char(
|
|
|
|
+ &mut self,
|
|
|
|
+ tty: Arc<TtyCore>,
|
|
|
|
+ termios: &RwLockReadGuard<Termios>,
|
|
|
|
+ signal: Signal,
|
|
|
|
+ c: u8,
|
|
|
|
+ ) {
|
|
|
|
+ self.input_signal(tty.clone(), termios, signal);
|
|
|
|
+ if termios.input_mode.contains(InputMode::IXON) {
|
|
|
|
+ tty.tty_start();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if termios.local_mode.contains(LocalMode::ECHO) {
|
|
|
|
+ self.echo_char(c, termios);
|
|
|
|
+ self.commit_echoes(tty);
|
|
|
|
+ } else {
|
|
|
|
+ self.process_echoes(tty);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /// ## 处理输入信号
|
|
|
|
+ pub fn input_signal(
|
|
|
|
+ &mut self,
|
|
|
|
+ tty: Arc<TtyCore>,
|
|
|
|
+ termios: &RwLockReadGuard<Termios>,
|
|
|
|
+ signal: Signal,
|
|
|
|
+ ) {
|
|
|
|
+ // 先处理信号
|
|
|
|
+ let mut ctrl_info = tty.core().contorl_info_irqsave();
|
|
|
|
+ let pg = ctrl_info.pgid;
|
|
|
|
+ if pg.is_some() {
|
|
|
|
+ let _ = Syscall::kill(pg.unwrap(), signal as i32);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ ctrl_info.pgid = None;
|
|
|
|
+ ctrl_info.session = None;
|
|
|
|
+
|
|
|
|
+ if !termios.local_mode.contains(LocalMode::NOFLSH) {
|
|
|
|
+ // 重置
|
|
|
|
+ self.echo_head = 0;
|
|
|
|
+ self.echo_tail = 0;
|
|
|
|
+ self.echo_mark = 0;
|
|
|
|
+ self.echo_commit = 0;
|
|
|
|
+
|
|
|
|
+ let _ = tty.flush_buffer(tty.core());
|
|
|
|
+
|
|
|
|
+ self.read_head = 0;
|
|
|
|
+ self.canon_head = 0;
|
|
|
|
+ self.read_tail = 0;
|
|
|
|
+ self.line_start = 0;
|
|
|
|
+
|
|
|
|
+ self.erasing = false;
|
|
|
|
+ self.read_flags.set_all(false);
|
|
|
|
+ self.pushing = false;
|
|
|
|
+ self.lookahead_count = 0;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ pub fn receive_char(&mut self, c: u8, tty: Arc<TtyCore>) {
|
|
|
|
+ let termios = tty.core().termios();
|
|
|
|
+
|
|
|
|
+ if termios.local_mode.contains(LocalMode::ECHO) {
|
|
|
|
+ if self.erasing {
|
|
|
|
+ self.add_echo_byte(b'/');
|
|
|
|
+ self.erasing = false;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if self.canon_head == self.read_head {
|
|
|
|
+ self.add_echo_byte(EchoOperation::Start.to_u8());
|
|
|
|
+ self.add_echo_byte(EchoOperation::SetCanonCol.to_u8());
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ self.echo_char(c, &termios);
|
|
|
|
+ self.commit_echoes(tty.clone());
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if c == 0o377 && tty.core().termios().input_mode.contains(InputMode::PARMRK) {
|
|
|
|
+ self.add_read_byte(c);
|
|
|
|
+ }
|
|
|
|
+ self.add_read_byte(c);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ pub fn echo_char(&mut self, c: u8, termios: &RwLockReadGuard<Termios>) {
|
|
|
|
+ if c == EchoOperation::Start.to_u8() {
|
|
|
|
+ self.add_echo_byte(EchoOperation::Start.to_u8());
|
|
|
|
+ self.add_echo_byte(EchoOperation::Start.to_u8());
|
|
|
|
+ } else {
|
|
|
|
+ if termios.local_mode.contains(LocalMode::ECHOCTL)
|
|
|
|
+ && (c as char).is_control()
|
|
|
|
+ && c != b'\t'
|
|
|
|
+ {
|
|
|
|
+ self.add_echo_byte(EchoOperation::Start.to_u8());
|
|
|
|
+ }
|
|
|
|
+ self.add_echo_byte(c);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ pub fn echo_char_raw(&mut self, c: u8) {
|
|
|
|
+ if c == EchoOperation::Start.to_u8() {
|
|
|
|
+ self.add_echo_byte(EchoOperation::Start.to_u8());
|
|
|
|
+ self.add_echo_byte(EchoOperation::Start.to_u8());
|
|
|
|
+ } else {
|
|
|
|
+ self.add_echo_byte(c);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /// ## 提交echobuf里的数据显示
|
|
|
|
+ pub fn commit_echoes(&mut self, tty: Arc<TtyCore>) {
|
|
|
|
+ let head = self.echo_head;
|
|
|
|
+ self.echo_mark = head;
|
|
|
|
+ let old = self.echo_commit - self.echo_tail;
|
|
|
|
+
|
|
|
|
+ // 需要echo的字符个数
|
|
|
|
+ let nr = head - self.echo_tail;
|
|
|
|
+
|
|
|
|
+ if nr < ECHO_COMMIT_WATERMARK || nr % ECHO_BLOCK > old % ECHO_BLOCK {
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ self.echo_commit = head;
|
|
|
|
+ let echoed = self.echoes(tty.clone());
|
|
|
|
+
|
|
|
|
+ if echoed.is_ok() && echoed.unwrap() > 0 {
|
|
|
|
+ tty.flush_chars(tty.core());
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ pub fn add_echo_byte(&mut self, c: u8) {
|
|
|
|
+ self.echo_buf[ntty_buf_mask(self.echo_head)] = c;
|
|
|
|
+ self.echo_head += 1;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ pub fn add_read_byte(&mut self, c: u8) {
|
|
|
|
+ self.read_buf[ntty_buf_mask(self.read_head)] = c;
|
|
|
|
+ self.read_head += 1;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /// ### 将read_buffer的部分值置0
|
|
|
|
+ ///
|
|
|
|
+ /// 只会在规范模式和禁用echo下执行
|
|
|
|
+ #[inline]
|
|
|
|
+ pub fn zero_buffer(&mut self, offset: usize, size: usize) {
|
|
|
|
+ let offset = offset & (NTTY_BUFSIZE - 1);
|
|
|
|
+ if self.icanon && !self.echo {
|
|
|
|
+ let n = offset + size;
|
|
|
|
+ if n > NTTY_BUFSIZE {
|
|
|
|
+ for c in &mut self.read_buf[offset..NTTY_BUFSIZE] {
|
|
|
|
+ *c = 0
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ for c in &mut self.read_buf[0..(n - NTTY_BUFSIZE)] {
|
|
|
|
+ *c = 0
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ for c in &mut self.read_buf[offset..n] {
|
|
|
|
+ *c = 0
|
|
|
|
+ }
|
|
|
|
+ };
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /// ## 从ntty中拷贝数据
|
|
|
|
+ ///
|
|
|
|
+ /// ### 参数
|
|
|
|
+ ///
|
|
|
|
+ /// ### to: 存储数据
|
|
|
|
+ /// ### tail: 读取尾
|
|
|
|
+ pub fn ntty_copy(
|
|
|
|
+ &mut self,
|
|
|
|
+ to: &mut [u8],
|
|
|
|
+ tail: usize,
|
|
|
|
+ n: &mut usize,
|
|
|
|
+ ) -> Result<(), SystemError> {
|
|
|
|
+ if to.len() < *n {
|
|
|
|
+ *n = to.len();
|
|
|
|
+ // return Err(SystemError::EINVAL);
|
|
|
|
+ }
|
|
|
|
+ if tail > NTTY_BUFSIZE {
|
|
|
|
+ return Err(SystemError::EINVAL);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ let size = NTTY_BUFSIZE - tail;
|
|
|
|
+
|
|
|
|
+ if size < *n {
|
|
|
|
+ // 有一部分数据在头部,则先拷贝后面部分,再拷贝头部
|
|
|
|
+ // TODO: tty审计?
|
|
|
|
+ to[0..size].copy_from_slice(&self.read_buf[tail..(tail + size)]);
|
|
|
|
+ to[size..].copy_from_slice(&self.read_buf[(tail + size)..(*n + tail)]);
|
|
|
|
+ } else {
|
|
|
|
+ to[..*n].copy_from_slice(&self.read_buf[tail..(tail + *n)])
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ self.zero_buffer(tail, *n);
|
|
|
|
+
|
|
|
|
+ Ok(())
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /// ## 规范模式下跳过EOF
|
|
|
|
+ pub fn canon_skip_eof(&mut self) {
|
|
|
|
+ // 没有数据
|
|
|
|
+ if self.read_tail == self.canon_head {
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ let tail = self.read_tail & (NTTY_BUFSIZE - 1);
|
|
|
|
+
|
|
|
|
+ // 查看read_flags是否读取位置为特殊字符
|
|
|
|
+ if !self.read_flags.get(tail).unwrap() {
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 确保读取位置是'\0'字符
|
|
|
|
+ if self.read_buf[tail] != ControlCharIndex::DISABLE_CHAR {
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 处理该字符,将read_flagsw该位清除
|
|
|
|
+ self.read_flags.set(tail, false);
|
|
|
|
+ // 读取位置+1,即跳过该字符不做处理
|
|
|
|
+ self.read_tail += 1;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /// ## 在规范模式(canonical mode)下从读缓冲中复制一行
|
|
|
|
+ ///
|
|
|
|
+ /// 一次只拷贝一行
|
|
|
|
+ ///
|
|
|
|
+ /// ## 参数
|
|
|
|
+ /// ### dst: 存放数据
|
|
|
|
+ /// ### nr: 需要拷贝的数据大小
|
|
|
|
+ ///
|
|
|
|
+ /// ## 返回值
|
|
|
|
+ /// ### true: 表示一行未结束并且还有数据可读
|
|
|
|
+ /// ### false: 一行已结束或者没有数据可读
|
|
|
|
+ pub fn canon_copy_from_read_buf(
|
|
|
|
+ &mut self,
|
|
|
|
+ dst: &mut [u8],
|
|
|
|
+ nr: &mut usize,
|
|
|
|
+ offset: &mut usize,
|
|
|
|
+ ) -> Result<bool, SystemError> {
|
|
|
|
+ if *nr == 0 {
|
|
|
|
+ return Ok(false);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ let canon_head = self.canon_head;
|
|
|
|
+
|
|
|
|
+ // 取得能够读到的字符数,即canon_head - self.read_tail和nr最小值
|
|
|
|
+ let mut n = (*nr).min(canon_head - self.read_tail);
|
|
|
|
+
|
|
|
|
+ // 获得读尾index
|
|
|
|
+ let tail = self.read_tail & (NTTY_BUFSIZE - 1);
|
|
|
|
+
|
|
|
|
+ // 避免越界,这个size才是实际读取大小
|
|
|
|
+ let size = if tail + n > NTTY_BUFSIZE {
|
|
|
|
+ NTTY_BUFSIZE
|
|
|
|
+ } else {
|
|
|
|
+ tail + *nr
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ // 找到eol的坐标
|
|
|
|
+ let tmp = self.read_flags.next_index(tail);
|
|
|
|
+ // 找到的话即为坐标,未找到的话即为NTTY_BUFSIZE
|
|
|
|
+ let mut eol = if tmp.is_none() { size } else { tmp.unwrap() };
|
|
|
|
+ if eol > size {
|
|
|
|
+ eol = size
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 是否需要绕回缓冲区头部
|
|
|
|
+ let more = n - (size - tail);
|
|
|
|
+
|
|
|
|
+ // 是否找到eol
|
|
|
|
+ let found = if eol == NTTY_BUFSIZE && more > 0 {
|
|
|
|
+ // 需要返回头部
|
|
|
|
+ let ret = self.read_flags.first_index();
|
|
|
|
+ if ret.is_some() {
|
|
|
|
+ let tmp = ret.unwrap();
|
|
|
|
+ // 在头部范围内找到eol
|
|
|
|
+ if tmp < more {
|
|
|
|
+ eol = tmp;
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ eol = more;
|
|
|
|
+ }
|
|
|
|
+ eol != more
|
|
|
|
+ } else {
|
|
|
|
+ // 不需要返回头部
|
|
|
|
+ eol != size
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ n = eol - tail;
|
|
|
|
+ if n > NTTY_BUFSIZE {
|
|
|
|
+ // 减法溢出则加上BUFSIZE即可限制在0-NTTY_BUFSIZE内
|
|
|
|
+ n += NTTY_BUFSIZE;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 规范模式下实际扫描过的字符数,需要将eol计算在内
|
|
|
|
+ let count = if found { n + 1 } else { n };
|
|
|
|
+
|
|
|
|
+ // 表示这一行未结束
|
|
|
|
+ if !found || self.read_at(eol) != ControlCharIndex::DISABLE_CHAR {
|
|
|
|
+ n = count;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ self.ntty_copy(&mut dst[*offset..], tail, &mut n)?;
|
|
|
|
+ *nr -= n;
|
|
|
|
+ *offset += n;
|
|
|
|
+
|
|
|
|
+ if found {
|
|
|
|
+ self.read_flags.set(eol, false);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ self.read_tail += count;
|
|
|
|
+
|
|
|
|
+ if found {
|
|
|
|
+ if !self.pushing {
|
|
|
|
+ self.line_start = self.read_tail;
|
|
|
|
+ } else {
|
|
|
|
+ self.pushing = false;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // todo: 审计?
|
|
|
|
+ return Ok(false);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 这里是表示没有找到eol,根据是否还有数据可读返回
|
|
|
|
+ Ok(self.read_tail != canon_head)
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /// ## 根据终端的模式和输入缓冲区中的数据量,判断是否可读字符
|
|
|
|
+ pub fn input_available(&self, termios: RwLockReadGuard<Termios>, poll: bool) -> bool {
|
|
|
|
+ // 计算最小字符数
|
|
|
|
+ let amt = if poll
|
|
|
|
+ && termios.control_characters[ControlCharIndex::VTIME] as u32 == 0
|
|
|
|
+ && termios.control_characters[ControlCharIndex::VMIN] as u32 != 0
|
|
|
|
+ {
|
|
|
|
+ termios.control_characters[ControlCharIndex::VMIN] as usize
|
|
|
|
+ } else {
|
|
|
|
+ 1
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ // 规范模式且非拓展
|
|
|
|
+ if self.icanon && !termios.local_mode.contains(LocalMode::EXTPROC) {
|
|
|
|
+ return self.canon_head != self.read_tail;
|
|
|
|
+ } else {
|
|
|
|
+ return (self.commit_head - self.read_tail) >= amt;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /// ## 非规范模式下从read_buf读取数据
|
|
|
|
+ ///
|
|
|
|
+ /// ## 参数
|
|
|
|
+ /// ### termios: tty对应的termioss读锁守卫
|
|
|
|
+ /// ### dst: 存储读取数据
|
|
|
|
+ /// ### nr: 读取长度
|
|
|
|
+ ///
|
|
|
|
+ /// ## 返回值
|
|
|
|
+ /// ### true: 还有更多数据可读
|
|
|
|
+ /// ### false: 无更多数据可读
|
|
|
|
+ pub fn copy_from_read_buf(
|
|
|
|
+ &mut self,
|
|
|
|
+ termios: RwLockReadGuard<Termios>,
|
|
|
|
+ dst: &mut [u8],
|
|
|
|
+ nr: &mut usize,
|
|
|
|
+ offset: &mut usize,
|
|
|
|
+ ) -> Result<bool, SystemError> {
|
|
|
|
+ let head = self.commit_head;
|
|
|
|
+ let tail = self.read_tail & (NTTY_BUFSIZE - 1);
|
|
|
|
+
|
|
|
|
+ // 计算出可读的字符数
|
|
|
|
+ let mut n = (NTTY_BUFSIZE - tail).min(self.read_tail);
|
|
|
|
+ n = n.min(*nr);
|
|
|
|
+
|
|
|
|
+ if n > 0 {
|
|
|
|
+ // 拷贝数据
|
|
|
|
+ self.ntty_copy(&mut dst[*offset..], tail, &mut n)?;
|
|
|
|
+ // todo:审计?
|
|
|
|
+ self.read_tail += n;
|
|
|
|
+
|
|
|
|
+ // 是否只读取了eof
|
|
|
|
+ let eof =
|
|
|
|
+ n == 1 && self.read_buf[tail] == termios.control_characters[ControlCharIndex::VEOF];
|
|
|
|
+
|
|
|
|
+ if termios.local_mode.contains(LocalMode::EXTPROC)
|
|
|
|
+ && self.icanon
|
|
|
|
+ && eof
|
|
|
|
+ && head == self.read_tail
|
|
|
|
+ {
|
|
|
|
+ return Ok(false);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ *nr -= n;
|
|
|
|
+ *offset += n;
|
|
|
|
+
|
|
|
|
+ return Ok(head != self.read_tail);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ Ok(false)
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /// ## 用于处理带有 OPOST(Output Post-processing)标志的输出块的函数
|
|
|
|
+ /// OPOST 是 POSIX 终端驱动器标志之一,用于指定在写入终端设备之前对输出数据进行一些后期处理。
|
|
|
|
+ pub fn process_output_block(
|
|
|
|
+ &mut self,
|
|
|
|
+ core: &TtyCoreData,
|
|
|
|
+ termios: RwLockReadGuard<Termios>,
|
|
|
|
+ buf: &[u8],
|
|
|
|
+ nr: usize,
|
|
|
|
+ ) -> Result<usize, SystemError> {
|
|
|
|
+ let mut nr = nr;
|
|
|
|
+ let tty = self.tty.clone().unwrap().upgrade().unwrap();
|
|
|
|
+ let space = tty.write_room(tty.core());
|
|
|
|
+
|
|
|
|
+ // 如果读取数量大于了可用空间,则取最小的为真正的写入数量
|
|
|
|
+ if nr > space {
|
|
|
|
+ nr = space
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ let mut cnt = 0;
|
|
|
|
+ for i in 0..nr {
|
|
|
|
+ cnt = i;
|
|
|
|
+ let c = buf[i];
|
|
|
|
+ if c as usize == 8 {
|
|
|
|
+ // 表示退格
|
|
|
|
+ if self.cursor_column > 0 {
|
|
|
|
+ self.cursor_column -= 1;
|
|
|
|
+ }
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
|
|
+ match c as char {
|
|
|
|
+ '\n' => {
|
|
|
|
+ if termios.output_mode.contains(OutputMode::ONLRET) {
|
|
|
|
+ // 将回车映射为\n,即将\n换为回车
|
|
|
|
+ self.cursor_column = 0;
|
|
|
|
+ }
|
|
|
|
+ if termios.output_mode.contains(OutputMode::ONLCR) {
|
|
|
|
+ // 输出时将\n换为\r\n
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ self.canon_cursor_column = self.cursor_column;
|
|
|
|
+ }
|
|
|
|
+ '\r' => {
|
|
|
|
+ if termios.output_mode.contains(OutputMode::ONOCR) && self.cursor_column == 0 {
|
|
|
|
+ // 光标已经在第0列,则不输出回车符
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if termios.output_mode.contains(OutputMode::OCRNL) {
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ self.canon_cursor_column = self.cursor_column;
|
|
|
|
+ }
|
|
|
|
+ '\t' => {
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ _ => {
|
|
|
|
+ // 判断是否为控制字符
|
|
|
|
+ if !(c as char).is_control() {
|
|
|
|
+ if termios.output_mode.contains(OutputMode::OLCUC) {
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 判断是否为utf8模式下的连续字符
|
|
|
|
+ if !(termios.input_mode.contains(InputMode::IUTF8)
|
|
|
|
+ && (c as usize) & 0xc0 == 0x80)
|
|
|
|
+ {
|
|
|
|
+ self.cursor_column += 1;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ drop(termios);
|
|
|
|
+ return tty.write(core, buf, cnt);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /// ## 处理回显
|
|
|
|
+ pub fn process_echoes(&mut self, tty: Arc<TtyCore>) {
|
|
|
|
+ if self.echo_mark == self.echo_tail {
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ self.echo_commit = self.echo_mark;
|
|
|
|
+ let echoed = self.echoes(tty.clone());
|
|
|
|
+
|
|
|
|
+ if echoed.is_ok() && echoed.unwrap() > 0 {
|
|
|
|
+ let _ = tty.flush_chars(tty.core());
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ pub fn echoes(&mut self, tty: Arc<TtyCore>) -> Result<usize, SystemError> {
|
|
|
|
+ let mut space = tty.write_room(tty.core());
|
|
|
|
+ let ospace = space;
|
|
|
|
+ let termios = tty.core().termios();
|
|
|
|
+ let core = tty.core();
|
|
|
|
+ let mut tail = self.echo_tail;
|
|
|
|
+
|
|
|
|
+ while ntty_buf_mask(self.echo_commit) != ntty_buf_mask(tail) {
|
|
|
|
+ let c = self.echo_buf[ntty_buf_mask(tail)];
|
|
|
|
+
|
|
|
|
+ if EchoOperation::from_u8(c) == EchoOperation::Start {
|
|
|
|
+ if ntty_buf_mask(self.echo_commit) == ntty_buf_mask(tail + 1) {
|
|
|
|
+ self.echo_tail = tail;
|
|
|
|
+ return Ok(ospace - space);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 获取到start,之后取第一个作为op
|
|
|
|
+ let op = EchoOperation::from_u8(self.echo_buf[ntty_buf_mask(tail + 1)]);
|
|
|
|
+
|
|
|
|
+ match op {
|
|
|
|
+ EchoOperation::Start => {
|
|
|
|
+ if space == 0 {
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if tty
|
|
|
|
+ .put_char(tty.core(), EchoOperation::Start.to_u8())
|
|
|
|
+ .is_err()
|
|
|
|
+ {
|
|
|
|
+ tty.write(core, &[EchoOperation::Start.to_u8()], 1)?;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ self.cursor_column += 1;
|
|
|
|
+ space -= 1;
|
|
|
|
+ tail += 2;
|
|
|
|
+ }
|
|
|
|
+ EchoOperation::MoveBackCol => {
|
|
|
|
+ if self.cursor_column > 0 {
|
|
|
|
+ self.cursor_column -= 1;
|
|
|
|
+ }
|
|
|
|
+ tail += 2;
|
|
|
|
+ }
|
|
|
|
+ EchoOperation::SetCanonCol => {
|
|
|
|
+ self.canon_cursor_column = self.cursor_column;
|
|
|
|
+ tail += 2;
|
|
|
|
+ }
|
|
|
|
+ EchoOperation::EraseTab => {
|
|
|
|
+ if ntty_buf_mask(self.echo_commit) == ntty_buf_mask(tail + 2) {
|
|
|
|
+ self.echo_tail = tail;
|
|
|
|
+ return Ok(ospace - space);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 要擦除的制表符所占用的列数
|
|
|
|
+ let mut char_num = self.echo_buf[ntty_buf_mask(tail + 2)] as usize;
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ 如果 num_chars 的最高位(0x80)未设置,
|
|
|
|
+ 表示这是从输入的起始位置而不是从先前的制表符开始计算的列数。
|
|
|
|
+ 在这种情况下,将 num_chars 与 ldata->canon_column 相加,否则,列数就是正常的制表符列数。
|
|
|
|
+ */
|
|
|
|
+ if char_num & 0x80 == 0 {
|
|
|
|
+ char_num += self.canon_cursor_column as usize;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 计算要回退的列数,即制表符宽度减去实际占用的列数
|
|
|
|
+ let mut num_bs = 8 - (char_num & 7);
|
|
|
|
+ if num_bs > space {
|
|
|
|
+ // 表示左边没有足够空间回退
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ space -= num_bs;
|
|
|
|
+ while num_bs != 0 {
|
|
|
|
+ num_bs -= 1;
|
|
|
|
+ // 8 => '\b'
|
|
|
|
+ if tty.put_char(tty.core(), 8).is_err() {
|
|
|
|
+ tty.write(core, &[8], 1)?;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if self.cursor_column > 0 {
|
|
|
|
+ self.cursor_column -= 1;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 已经读取了 tail tail+1 tail+2,所以这里偏移加3
|
|
|
|
+ tail += 3;
|
|
|
|
+ }
|
|
|
|
+ EchoOperation::Undefined(ch) => {
|
|
|
|
+ match ch {
|
|
|
|
+ 8 => {
|
|
|
|
+ if tty.put_char(tty.core(), 8).is_err() {
|
|
|
|
+ tty.write(core, &[8], 1)?;
|
|
|
|
+ }
|
|
|
|
+ if tty.put_char(tty.core(), ' ' as u8).is_err() {
|
|
|
|
+ tty.write(core, &[' ' as u8], 1)?;
|
|
|
|
+ }
|
|
|
|
+ self.cursor_column -= 1;
|
|
|
|
+ space -= 1;
|
|
|
|
+ tail += 1;
|
|
|
|
+ }
|
|
|
|
+ _ => {
|
|
|
|
+ // 不是特殊字节码,则表示控制字符 例如 ^C
|
|
|
|
+ if space < 2 {
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if tty.put_char(tty.core(), b'^').is_err() {
|
|
|
|
+ tty.write(core, &[b'^'], 1)?;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if tty.put_char(tty.core(), ch ^ 0o100).is_err() {
|
|
|
|
+ tty.write(core, &[ch ^ 0o100], 1)?;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ self.cursor_column += 2;
|
|
|
|
+ space -= 2;
|
|
|
|
+ tail += 2;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ if termios.output_mode.contains(OutputMode::OPOST) {
|
|
|
|
+ let ret = self.do_output_char(tty.clone(), c, space);
|
|
|
|
+
|
|
|
|
+ if ret.is_err() {
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ space -= ret.unwrap();
|
|
|
|
+ } else {
|
|
|
|
+ if space == 0 {
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if tty.put_char(tty.core(), c).is_err() {
|
|
|
|
+ tty.write(core, &[c], 1)?;
|
|
|
|
+ }
|
|
|
|
+ space -= 1;
|
|
|
|
+ }
|
|
|
|
+ tail += 1;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 如果回显缓冲区接近满(在下一次提交之前可能会发生回显溢出的情况),则丢弃足够的尾部数据以防止随后的溢出。
|
|
|
|
+ while self.echo_commit > tail && self.echo_commit - tail >= ECHO_DISCARD_WATERMARK {
|
|
|
|
+ if self.echo_buf[ntty_buf_mask(tail)] == EchoOperation::Start.to_u8() {
|
|
|
|
+ if self.echo_buf[ntty_buf_mask(tail + 1)] == EchoOperation::EraseTab.to_u8() {
|
|
|
|
+ tail += 3;
|
|
|
|
+ } else {
|
|
|
|
+ tail += 2;
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ tail += 1;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ self.echo_tail = tail;
|
|
|
|
+ return Ok(ospace - space);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /// ## 处理输出字符(带有 OPOST 处理)
|
|
|
|
+ pub fn process_output(&mut self, tty: Arc<TtyCore>, c: u8) -> bool {
|
|
|
|
+ let space = tty.write_room(tty.core());
|
|
|
|
+
|
|
|
|
+ if self.do_output_char(tty, c, space).is_err() {
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ true
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // ## 设置带有 OPOST 处理的tty输出一个字符
|
|
|
|
+ pub fn do_output_char(
|
|
|
|
+ &mut self,
|
|
|
|
+ tty: Arc<TtyCore>,
|
|
|
|
+ c: u8,
|
|
|
|
+ space: usize,
|
|
|
|
+ ) -> Result<usize, SystemError> {
|
|
|
|
+ if space == 0 {
|
|
|
|
+ return Err(SystemError::ENOBUFS);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ let termios = tty.core().termios();
|
|
|
|
+ let core = tty.core();
|
|
|
|
+ let mut c = c;
|
|
|
|
+ if c as usize == 8 {
|
|
|
|
+ // 表示退格
|
|
|
|
+ if self.cursor_column > 0 {
|
|
|
|
+ self.cursor_column -= 1;
|
|
|
|
+ }
|
|
|
|
+ if tty.put_char(tty.core(), c).is_err() {
|
|
|
|
+ tty.write(core, &[c], 1)?;
|
|
|
|
+ }
|
|
|
|
+ return Ok(1);
|
|
|
|
+ }
|
|
|
|
+ match c as char {
|
|
|
|
+ '\n' => {
|
|
|
|
+ if termios.output_mode.contains(OutputMode::ONLRET) {
|
|
|
|
+ // 回车符
|
|
|
|
+ self.cursor_column = 0;
|
|
|
|
+ }
|
|
|
|
+ if termios.output_mode.contains(OutputMode::ONLCR) {
|
|
|
|
+ // 映射为“\r\n”
|
|
|
|
+ if space < 2 {
|
|
|
|
+ return Err(SystemError::ENOBUFS);
|
|
|
|
+ }
|
|
|
|
+ self.cursor_column = 0;
|
|
|
|
+ self.canon_cursor_column = 0;
|
|
|
|
+
|
|
|
|
+ // 通过驱动写入
|
|
|
|
+ tty.write(core, "\r\n".as_bytes(), 2)?;
|
|
|
|
+ return Ok(2);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ self.canon_cursor_column = self.cursor_column;
|
|
|
|
+ }
|
|
|
|
+ '\r' => {
|
|
|
|
+ if termios.output_mode.contains(OutputMode::ONOCR) && self.cursor_column == 0 {
|
|
|
|
+ // 光标已经在第0列,则不输出回车符
|
|
|
|
+ return Ok(0);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if termios.output_mode.contains(OutputMode::OCRNL) {
|
|
|
|
+ // 输出的\r映射为\n
|
|
|
|
+ c = b'\n';
|
|
|
|
+ if termios.output_mode.contains(OutputMode::ONLRET) {
|
|
|
|
+ // \r映射为\n,但是保留\r特性
|
|
|
|
+ self.cursor_column = 0;
|
|
|
|
+ self.canon_cursor_column = 0;
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ self.cursor_column = 0;
|
|
|
|
+ self.canon_cursor_column = 0;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ '\t' => {
|
|
|
|
+ // 计算输出一个\t需要的空间
|
|
|
|
+ let spaces = 8 - (self.cursor_column & 7) as usize;
|
|
|
|
+ if termios.output_mode.contains(OutputMode::TABDLY) {
|
|
|
|
+ if OutputMode::TABDLY.bits() == OutputMode::XTABS.bits() {
|
|
|
|
+ // 配置的tab选项是真正输出空格到驱动
|
|
|
|
+ if space < spaces {
|
|
|
|
+ // 空间不够
|
|
|
|
+ return Err(SystemError::ENOBUFS);
|
|
|
|
+ }
|
|
|
|
+ self.cursor_column += spaces as u32;
|
|
|
|
+ // 写入sapces个空格
|
|
|
|
+ tty.write(core, " ".as_bytes(), spaces)?;
|
|
|
|
+ return Ok(spaces);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ self.cursor_column += spaces as u32;
|
|
|
|
+ }
|
|
|
|
+ _ => {
|
|
|
|
+ // 判断是否为控制字符
|
|
|
|
+ if !(c as char).is_control() {
|
|
|
|
+ if termios.output_mode.contains(OutputMode::OLCUC) {
|
|
|
|
+ c = c.to_ascii_uppercase();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 判断是否为utf8模式下的连续字符
|
|
|
|
+ if !(termios.input_mode.contains(InputMode::IUTF8)
|
|
|
|
+ && (c as usize) & 0xc0 == 0x80)
|
|
|
|
+ {
|
|
|
|
+ self.cursor_column += 1;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if tty.put_char(tty.core(), c).is_err() {
|
|
|
|
+ tty.write(core, &[c], 1)?;
|
|
|
|
+ }
|
|
|
|
+ Ok(1)
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+impl TtyLineDiscipline for NTtyLinediscipline {
|
|
|
|
+ fn open(&self, tty: Arc<TtyCore>) -> Result<(), system_error::SystemError> {
|
|
|
|
+ // 反向绑定tty到disc
|
|
|
|
+ self.disc_data().tty = Some(Arc::downgrade(&tty));
|
|
|
|
+ // 特定的tty设备在这里可能需要取消端口节流
|
|
|
|
+ return self.set_termios(tty, None);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ fn close(&self, _tty: Arc<TtyCore>) -> Result<(), system_error::SystemError> {
|
|
|
|
+ todo!()
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /// ## 重置缓冲区的基本信息
|
|
|
|
+ fn flush_buffer(&self, tty: Arc<TtyCore>) -> Result<(), system_error::SystemError> {
|
|
|
|
+ let core = tty.core();
|
|
|
|
+ let _ = core.termios();
|
|
|
|
+ let mut ldata = self.disc_data();
|
|
|
|
+ ldata.read_head = 0;
|
|
|
|
+ ldata.canon_head = 0;
|
|
|
|
+ ldata.read_tail = 0;
|
|
|
|
+ ldata.commit_head = 0;
|
|
|
|
+ ldata.line_start = 0;
|
|
|
|
+ ldata.erasing = false;
|
|
|
|
+ ldata.read_flags.set_all(false);
|
|
|
|
+ ldata.pushing = false;
|
|
|
|
+ ldata.lookahead_count = 0;
|
|
|
|
+
|
|
|
|
+ // todo: kick worker?
|
|
|
|
+ // todo: packet mode?
|
|
|
|
+
|
|
|
|
+ Ok(())
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ fn read(
|
|
|
|
+ &self,
|
|
|
|
+ tty: Arc<TtyCore>,
|
|
|
|
+ buf: &mut [u8],
|
|
|
|
+ len: usize,
|
|
|
|
+ cookie: &mut bool,
|
|
|
|
+ _offset: usize,
|
|
|
|
+ mode: FileMode,
|
|
|
|
+ ) -> Result<usize, system_error::SystemError> {
|
|
|
|
+ let mut ldata;
|
|
|
|
+ if mode.contains(FileMode::O_NONBLOCK) {
|
|
|
|
+ let ret = self.disc_data_try_lock();
|
|
|
|
+ if ret.is_err() {
|
|
|
|
+ return Err(SystemError::EAGAIN_OR_EWOULDBLOCK);
|
|
|
|
+ }
|
|
|
|
+ ldata = ret.unwrap();
|
|
|
|
+ } else {
|
|
|
|
+ ldata = self.disc_data();
|
|
|
|
+ }
|
|
|
|
+ let core = tty.core();
|
|
|
|
+ let termios = core.termios();
|
|
|
|
+ let mut nr = len;
|
|
|
|
+
|
|
|
|
+ let mut offset = 0;
|
|
|
|
+
|
|
|
|
+ // 表示接着读
|
|
|
|
+ if *cookie {
|
|
|
|
+ // 规范且非拓展模式
|
|
|
|
+ if ldata.icanon && !termios.local_mode.contains(LocalMode::EXTPROC) {
|
|
|
|
+ // 跳过EOF字符
|
|
|
|
+ if len == 0 {
|
|
|
|
+ ldata.canon_skip_eof();
|
|
|
|
+ } else if ldata.canon_copy_from_read_buf(buf, &mut nr, &mut offset)? {
|
|
|
|
+ return Ok(len - nr);
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ if ldata.canon_copy_from_read_buf(buf, &mut nr, &mut offset)? {
|
|
|
|
+ return Ok(len - nr);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 没有数据可读
|
|
|
|
+
|
|
|
|
+ // todo: kick worker? or 关闭节流?
|
|
|
|
+
|
|
|
|
+ *cookie = false;
|
|
|
|
+ return Ok(len - nr);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ drop(termios);
|
|
|
|
+
|
|
|
|
+ TtyJobCtrlManager::tty_check_change(tty.clone(), Signal::SIGTTIN)?;
|
|
|
|
+
|
|
|
|
+ let mut minimum: usize = 0;
|
|
|
|
+ if !ldata.icanon {
|
|
|
|
+ let core = tty.core();
|
|
|
|
+ let termios = core.termios();
|
|
|
|
+ minimum = termios.control_characters[ControlCharIndex::VMIN] as usize;
|
|
|
|
+ if minimum == 0 {
|
|
|
|
+ minimum = 1;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ let mut ret: Result<usize, SystemError> = Ok(0);
|
|
|
|
+ // 记录读取前 的tail
|
|
|
|
+ let tail = ldata.read_tail;
|
|
|
|
+ drop(ldata);
|
|
|
|
+ while nr != 0 {
|
|
|
|
+ // todo: 处理packet模式
|
|
|
|
+ let mut ldata = self.disc_data();
|
|
|
|
+
|
|
|
|
+ let core = tty.core();
|
|
|
|
+ if !ldata.input_available(core.termios(), false) {
|
|
|
|
+ if core.flags().contains(TtyFlag::OTHER_CLOSED) {
|
|
|
|
+ ret = Err(SystemError::EIO);
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if core.flags().contains(TtyFlag::HUPPED) || core.flags().contains(TtyFlag::HUPPING)
|
|
|
|
+ {
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if mode.contains(FileMode::O_NONBLOCK)
|
|
|
|
+ || core.flags().contains(TtyFlag::LDISC_CHANGING)
|
|
|
|
+ {
|
|
|
|
+ ret = Err(SystemError::EAGAIN_OR_EWOULDBLOCK);
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if ProcessManager::current_pcb()
|
|
|
|
+ .sig_info()
|
|
|
|
+ .sig_pending()
|
|
|
|
+ .has_pending()
|
|
|
|
+ {
|
|
|
|
+ ret = Err(SystemError::ERESTARTSYS);
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 休眠一段时间
|
|
|
|
+ // 获取到termios读锁,避免termios被更改导致行为异常
|
|
|
|
+ // let termios = core.termios_preempt_enable();
|
|
|
|
+ // let helper = WakeUpHelper::new(ProcessManager::current_pcb());
|
|
|
|
+ // let wakeup_helper = Timer::new(helper, timeout);
|
|
|
|
+ // wakeup_helper.activate();
|
|
|
|
+ // drop(termios);
|
|
|
|
+ drop(ldata);
|
|
|
|
+ core.read_wq()
|
|
|
|
+ .sleep((EPollEventType::EPOLLIN | EPollEventType::EPOLLRDNORM).bits() as u64);
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if ldata.icanon && !core.termios().local_mode.contains(LocalMode::EXTPROC) {
|
|
|
|
+ if ldata.canon_copy_from_read_buf(buf, &mut nr, &mut offset)? {
|
|
|
|
+ *cookie = true;
|
|
|
|
+ offset += len - nr;
|
|
|
|
+ return Ok(offset);
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ // 非标准模式
|
|
|
|
+ // todo: 处理packet模式
|
|
|
|
+
|
|
|
|
+ // 拷贝数据
|
|
|
|
+ if ldata.copy_from_read_buf(core.termios(), buf, &mut nr, &mut offset)?
|
|
|
|
+ && offset >= minimum
|
|
|
|
+ {
|
|
|
|
+ *cookie = true;
|
|
|
|
+ return Ok(offset);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if offset >= minimum {
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ let ldata = self.disc_data();
|
|
|
|
+ if tail != ldata.read_tail {
|
|
|
|
+ // todo: kick worker?
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if offset > 0 {
|
|
|
|
+ return Ok(offset);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ ret
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ fn write(
|
|
|
|
+ &self,
|
|
|
|
+ tty: Arc<TtyCore>,
|
|
|
|
+ buf: &[u8],
|
|
|
|
+ len: usize,
|
|
|
|
+ mode: FileMode,
|
|
|
|
+ ) -> Result<usize, system_error::SystemError> {
|
|
|
|
+ let mut nr = len;
|
|
|
|
+ let mut ldata = self.disc_data();
|
|
|
|
+ let pcb = ProcessManager::current_pcb();
|
|
|
|
+ let binding = tty.clone();
|
|
|
|
+ let core = binding.core();
|
|
|
|
+ let termios = core.termios().clone();
|
|
|
|
+ if termios.local_mode.contains(LocalMode::TOSTOP) {
|
|
|
|
+ TtyJobCtrlManager::tty_check_change(tty.clone(), Signal::SIGTTOU)?;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ ldata.process_echoes(tty.clone());
|
|
|
|
+ // drop(ldata);
|
|
|
|
+ let mut offset = 0;
|
|
|
|
+ loop {
|
|
|
|
+ if pcb.sig_info().sig_pending().has_pending() {
|
|
|
|
+ return Err(SystemError::ERESTARTSYS);
|
|
|
|
+ }
|
|
|
|
+ if core.flags().contains(TtyFlag::HUPPED) {
|
|
|
|
+ return Err(SystemError::EIO);
|
|
|
|
+ }
|
|
|
|
+ if termios.output_mode.contains(OutputMode::OPOST) {
|
|
|
|
+ while nr > 0 {
|
|
|
|
+ // let mut ldata = self.disc_data();
|
|
|
|
+ // 获得一次处理后的数量
|
|
|
|
+ let ret = ldata.process_output_block(core, core.termios(), &buf[offset..], nr);
|
|
|
|
+ let num = match ret {
|
|
|
|
+ Ok(num) => num,
|
|
|
|
+ Err(e) => {
|
|
|
|
+ if e == SystemError::EAGAIN_OR_EWOULDBLOCK {
|
|
|
|
+ break;
|
|
|
|
+ } else {
|
|
|
|
+ return Err(e);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ offset += num;
|
|
|
|
+ nr -= num;
|
|
|
|
+
|
|
|
|
+ if nr == 0 {
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ let c = buf[offset];
|
|
|
|
+ if !ldata.process_output(tty.clone(), c) {
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ offset += 1;
|
|
|
|
+ nr -= 1;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ let _ = tty.flush_chars(core);
|
|
|
|
+ } else {
|
|
|
|
+ while nr > 0 {
|
|
|
|
+ let write = tty.write(core, &buf[offset..], nr)?;
|
|
|
|
+ if write == 0 {
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ offset += write;
|
|
|
|
+ nr -= write;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if nr == 0 {
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if mode.contains(FileMode::O_NONBLOCK) || core.flags().contains(TtyFlag::LDISC_CHANGING)
|
|
|
|
+ {
|
|
|
|
+ return Err(SystemError::EAGAIN_OR_EWOULDBLOCK);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 到这里表明没位置可写了
|
|
|
|
+ // 休眠一段时间
|
|
|
|
+ // 获取到termios读锁,避免termios被更改导致行为异常
|
|
|
|
+ core.write_wq()
|
|
|
|
+ .sleep(EPollEventType::EPOLLOUT.bits() as u64);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ Ok(offset)
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ fn ioctl(
|
|
|
|
+ &self,
|
|
|
|
+ tty: Arc<TtyCore>,
|
|
|
|
+ cmd: u32,
|
|
|
|
+ arg: usize,
|
|
|
|
+ ) -> Result<usize, system_error::SystemError> {
|
|
|
|
+ match cmd {
|
|
|
|
+ TtyIoctlCmd::TIOCOUTQ => {
|
|
|
|
+ let mut user_writer = UserBufferWriter::new(
|
|
|
|
+ VirtAddr::new(arg).as_ptr::<i32>(),
|
|
|
|
+ core::mem::size_of::<i32>(),
|
|
|
|
+ true,
|
|
|
|
+ )?;
|
|
|
|
+
|
|
|
|
+ let count = tty.chars_in_buffer();
|
|
|
|
+ user_writer.copy_one_to_user::<i32>(&(count as i32), 0)?;
|
|
|
|
+ return Ok(0);
|
|
|
|
+ }
|
|
|
|
+ TtyIoctlCmd::FIONREAD => {
|
|
|
|
+ let ldata = self.disc_data();
|
|
|
|
+ let termios = tty.core().termios();
|
|
|
|
+ let retval;
|
|
|
|
+ if termios.local_mode.contains(LocalMode::ICANON)
|
|
|
|
+ && !termios.local_mode.contains(LocalMode::EXTPROC)
|
|
|
|
+ {
|
|
|
|
+ if ldata.canon_head == ldata.read_tail {
|
|
|
|
+ retval = 0;
|
|
|
|
+ } else {
|
|
|
|
+ let head = ldata.canon_head;
|
|
|
|
+ let mut tail = ldata.read_tail;
|
|
|
|
+ let mut nr = head - tail;
|
|
|
|
+
|
|
|
|
+ while ntty_buf_mask(head) != ntty_buf_mask(tail) {
|
|
|
|
+ if ldata.read_flags.get(ntty_buf_mask(tail)).unwrap()
|
|
|
|
+ && ldata.read_buf[ntty_buf_mask(tail)]
|
|
|
|
+ == ControlCharIndex::DISABLE_CHAR
|
|
|
|
+ {
|
|
|
|
+ nr -= 1;
|
|
|
|
+ }
|
|
|
|
+ tail += 1;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ retval = nr;
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ retval = ldata.read_cnt();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ let mut user_writer = UserBufferWriter::new(
|
|
|
|
+ VirtAddr::new(arg).as_ptr::<i32>(),
|
|
|
|
+ core::mem::size_of::<i32>(),
|
|
|
|
+ true,
|
|
|
|
+ )?;
|
|
|
|
+
|
|
|
|
+ user_writer.copy_one_to_user::<i32>(&(retval as i32), 0)?;
|
|
|
|
+ return Ok(0);
|
|
|
|
+ }
|
|
|
|
+ _ => {
|
|
|
|
+ return self.ioctl_helper(tty, cmd, arg);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ fn set_termios(
|
|
|
|
+ &self,
|
|
|
|
+ tty: Arc<TtyCore>,
|
|
|
|
+ old: Option<crate::driver::tty::termios::Termios>,
|
|
|
|
+ ) -> Result<(), system_error::SystemError> {
|
|
|
|
+ let core = tty.core();
|
|
|
|
+ let termios = core.termios();
|
|
|
|
+ let mut ldata = self.disc_data();
|
|
|
|
+ let contorl_chars = termios.control_characters;
|
|
|
|
+
|
|
|
|
+ // 第一次设置或者规范模式 (ICANON) 或者扩展处理 (EXTPROC) 标志发生变化
|
|
|
|
+ if old.is_none()
|
|
|
|
+ || (old.is_some()
|
|
|
|
+ && old
|
|
|
|
+ .unwrap()
|
|
|
|
+ .local_mode
|
|
|
|
+ .bitxor(termios.local_mode)
|
|
|
|
+ .contains(LocalMode::ICANON | LocalMode::EXTPROC))
|
|
|
|
+ {
|
|
|
|
+ // 重置read_flags
|
|
|
|
+ ldata.read_flags.set_all(false);
|
|
|
|
+
|
|
|
|
+ ldata.line_start = ldata.read_tail;
|
|
|
|
+
|
|
|
|
+ // 不是规范模式或者有可读数据
|
|
|
|
+ if !termios.local_mode.contains(LocalMode::ICANON) || ldata.read_cnt() != 0 {
|
|
|
|
+ ldata.canon_head = ldata.read_tail;
|
|
|
|
+ ldata.pushing = false;
|
|
|
|
+ } else {
|
|
|
|
+ let read_head = ldata.read_head;
|
|
|
|
+ ldata
|
|
|
|
+ .read_flags
|
|
|
|
+ .set((read_head - 1) & (NTTY_BUFSIZE - 1), true);
|
|
|
|
+ ldata.canon_head = ldata.read_head;
|
|
|
|
+ ldata.pushing = true;
|
|
|
|
+ }
|
|
|
|
+ ldata.commit_head = ldata.read_head;
|
|
|
|
+ ldata.erasing = false;
|
|
|
|
+ ldata.lnext = false;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 设置规范模式
|
|
|
|
+ if termios.local_mode.contains(LocalMode::ICANON) {
|
|
|
|
+ ldata.icanon = true;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 设置回显
|
|
|
|
+ if termios.local_mode.contains(LocalMode::ECHO) {
|
|
|
|
+ ldata.echo = true;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if termios.input_mode.contains(InputMode::ISTRIP)
|
|
|
|
+ || termios.input_mode.contains(InputMode::IUCLC)
|
|
|
|
+ || termios.input_mode.contains(InputMode::IGNCR)
|
|
|
|
+ || termios.input_mode.contains(InputMode::IXON)
|
|
|
|
+ || termios.local_mode.contains(LocalMode::ISIG)
|
|
|
|
+ || termios.local_mode.contains(LocalMode::ECHO)
|
|
|
|
+ || termios.input_mode.contains(InputMode::PARMRK)
|
|
|
|
+ {
|
|
|
|
+ // 非原模式
|
|
|
|
+
|
|
|
|
+ ldata.char_map.set_all(false);
|
|
|
|
+
|
|
|
|
+ // 忽略回车符或者将回车映射为换行符
|
|
|
|
+ if termios.input_mode.contains(InputMode::IGNCR)
|
|
|
|
+ || termios.input_mode.contains(InputMode::ICRNL)
|
|
|
|
+ {
|
|
|
|
+ ldata.char_map.set('\r' as usize, true);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 将换行映射为回车
|
|
|
|
+ if termios.input_mode.contains(InputMode::INLCR) {
|
|
|
|
+ ldata.char_map.set('\n' as usize, true);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 规范模式
|
|
|
|
+ if termios.local_mode.contains(LocalMode::ICANON) {
|
|
|
|
+ ldata
|
|
|
|
+ .char_map
|
|
|
|
+ .set(contorl_chars[ControlCharIndex::VERASE] as usize, true);
|
|
|
|
+ ldata
|
|
|
|
+ .char_map
|
|
|
|
+ .set(contorl_chars[ControlCharIndex::VKILL] as usize, true);
|
|
|
|
+ ldata
|
|
|
|
+ .char_map
|
|
|
|
+ .set(contorl_chars[ControlCharIndex::VEOF] as usize, true);
|
|
|
|
+ ldata.char_map.set('\n' as usize, true);
|
|
|
|
+ ldata
|
|
|
|
+ .char_map
|
|
|
|
+ .set(contorl_chars[ControlCharIndex::VEOL] as usize, true);
|
|
|
|
+
|
|
|
|
+ if termios.local_mode.contains(LocalMode::IEXTEN) {
|
|
|
|
+ ldata
|
|
|
|
+ .char_map
|
|
|
|
+ .set(contorl_chars[ControlCharIndex::VWERASE] as usize, true);
|
|
|
|
+ ldata
|
|
|
|
+ .char_map
|
|
|
|
+ .set(contorl_chars[ControlCharIndex::VLNEXT] as usize, true);
|
|
|
|
+ ldata
|
|
|
|
+ .char_map
|
|
|
|
+ .set(contorl_chars[ControlCharIndex::VEOL2] as usize, true);
|
|
|
|
+ if termios.local_mode.contains(LocalMode::ECHO) {
|
|
|
|
+ ldata
|
|
|
|
+ .char_map
|
|
|
|
+ .set(contorl_chars[ControlCharIndex::VREPRINT] as usize, true);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 软件流控制
|
|
|
|
+ if termios.input_mode.contains(InputMode::IXON) {
|
|
|
|
+ ldata
|
|
|
|
+ .char_map
|
|
|
|
+ .set(contorl_chars[ControlCharIndex::VSTART] as usize, true);
|
|
|
|
+ ldata
|
|
|
|
+ .char_map
|
|
|
|
+ .set(contorl_chars[ControlCharIndex::VSTOP] as usize, true);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if termios.local_mode.contains(LocalMode::ISIG) {
|
|
|
|
+ ldata
|
|
|
|
+ .char_map
|
|
|
|
+ .set(contorl_chars[ControlCharIndex::VINTR] as usize, true);
|
|
|
|
+ ldata
|
|
|
|
+ .char_map
|
|
|
|
+ .set(contorl_chars[ControlCharIndex::VQUIT] as usize, true);
|
|
|
|
+ ldata
|
|
|
|
+ .char_map
|
|
|
|
+ .set(contorl_chars[ControlCharIndex::VSUSP] as usize, true);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ ldata
|
|
|
|
+ .char_map
|
|
|
|
+ .set(ControlCharIndex::DISABLE_CHAR as usize, true);
|
|
|
|
+ ldata.raw = false;
|
|
|
|
+ ldata.real_raw = false;
|
|
|
|
+ } else {
|
|
|
|
+ // 原模式或real_raw
|
|
|
|
+ ldata.raw = true;
|
|
|
|
+
|
|
|
|
+ if termios.input_mode.contains(InputMode::IGNBRK)
|
|
|
|
+ || (!termios.input_mode.contains(InputMode::BRKINT)
|
|
|
|
+ && !termios.input_mode.contains(InputMode::PARMRK))
|
|
|
|
+ && (termios.input_mode.contains(InputMode::IGNPAR)
|
|
|
|
+ || !termios.input_mode.contains(InputMode::INPCK))
|
|
|
|
+ && (core
|
|
|
|
+ .driver()
|
|
|
|
+ .flags()
|
|
|
|
+ .contains(TtyDriverFlag::TTY_DRIVER_REAL_RAW))
|
|
|
|
+ {
|
|
|
|
+ ldata.real_raw = true;
|
|
|
|
+ } else {
|
|
|
|
+ ldata.real_raw = false;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // if !termios.input_mode.contains(InputMode::IXON)
|
|
|
|
+ // && old.is_some()
|
|
|
|
+ // && old.unwrap().input_mode.contains(InputMode::IXON) && !
|
|
|
|
+ // {}
|
|
|
|
+
|
|
|
|
+ core.read_wq().wakeup_all();
|
|
|
|
+ core.write_wq().wakeup_all();
|
|
|
|
+ Ok(())
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ fn poll(&self, _tty: Arc<TtyCore>) -> Result<(), system_error::SystemError> {
|
|
|
|
+ todo!()
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ fn hangup(&self, _tty: Arc<TtyCore>) -> Result<(), system_error::SystemError> {
|
|
|
|
+ todo!()
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ fn receive_buf(
|
|
|
|
+ &self,
|
|
|
|
+ tty: Arc<TtyCore>,
|
|
|
|
+ buf: &[u8],
|
|
|
|
+ flags: Option<&[u8]>,
|
|
|
|
+ count: usize,
|
|
|
|
+ ) -> Result<usize, SystemError> {
|
|
|
|
+ let mut ldata = self.disc_data();
|
|
|
|
+ ldata.receive_buf_common(tty, buf, flags, count, false)
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ fn receive_buf2(
|
|
|
|
+ &self,
|
|
|
|
+ tty: Arc<TtyCore>,
|
|
|
|
+ buf: &[u8],
|
|
|
|
+ flags: Option<&[u8]>,
|
|
|
|
+ count: usize,
|
|
|
|
+ ) -> Result<usize, SystemError> {
|
|
|
|
+ let mut ldata = self.disc_data();
|
|
|
|
+ ldata.receive_buf_common(tty, buf, flags, count, true)
|
|
|
|
+ }
|
|
|
|
+}
|