1use derivative::Derivative;
6use starnix_uapi::errors::Errno;
7use starnix_uapi::signals::{SIGINT, SIGQUIT, SIGSTOP, Signal};
8use starnix_uapi::vfs::FdEvents;
9use starnix_uapi::{
10 ECHO, ECHOCTL, ECHOE, ECHOK, ECHOKE, ECHONL, ECHOPRT, ICANON, ICRNL, IEXTEN, IGNCR, INLCR,
11 ISIG, IUCLC, IUTF8, IXANY, IXON, NOFLSH, OCRNL, OLCUC, ONLCR, ONLRET, ONOCR, OPOST, TABDLY,
12 VEOF, VEOL, VEOL2, VERASE, VINTR, VKILL, VLNEXT, VQUIT, VREPRINT, VSTART, VSTOP, VSUSP,
13 VWERASE, XTABS, cc_t, error, tcflag_t, uapi,
14};
15use std::collections::VecDeque;
16
17const CANON_MAX_BYTES: usize = 4096;
20
21const NON_CANON_MAX_BYTES: usize = CANON_MAX_BYTES - 1;
24
25const WAIT_BUFFER_MAX_BYTES: usize = 131072;
28
29const SPACES_PER_TAB: usize = 8;
30
31const DISABLED_CHAR: u8 = 0;
33
34const BACKSPACE_CHAR: u8 = 8; const CONTROL_OFFSET: u8 = 0x40;
40
41#[derive(Derivative)]
42#[derivative(Default)]
43#[derivative(Debug)]
44pub struct LineDiscipline {
45 #[derivative(Default(value = "true"))]
47 pub locked: bool,
48
49 #[derivative(Default(value = "false"))]
51 pub stopped: bool,
52
53 pub window_size: uapi::winsize,
55
56 #[derivative(Default(value = "get_default_termios()"))]
58 termios: uapi::termios,
59
60 #[derivative(Default(value = "false"))]
62 erasing: bool,
63
64 #[derivative(Default(value = "false"))]
66 lnext: bool,
67
68 column: usize,
71
72 main_references: Option<u32>,
75
76 replica_references: Option<u32>,
79
80 #[derivative(Default(value = "Queue::input_queue()"))]
82 input_queue: Option<Queue>,
83
84 #[derivative(Default(value = "Queue::output_queue()"))]
86 output_queue: Option<Queue>,
87}
88
89pub trait InputBuffer {
91 fn available(&self) -> usize;
92 fn read_to_vec_exact(&mut self, size: usize) -> Result<Vec<u8>, Errno>;
93}
94
95pub trait OutputBuffer {
96 fn write(&mut self, data: &[u8]) -> Result<usize, Errno>;
97}
98
99macro_rules! with_queue {
101 ($self_:tt . $name:ident . $fn:ident ( $($param:expr),*$(,)?)) => {
102 {
103 let mut queue = $self_.$name . take().unwrap();
104 let result = queue.$fn( $($param),* );
105 $self_.$name = Some(queue);
106 result
107 }
108 };
109}
110
111#[must_use]
113pub struct PendingSignals {
114 signals: Vec<Signal>,
115}
116
117impl PendingSignals {
118 pub fn new() -> Self {
119 Self { signals: vec![] }
120 }
121
122 fn add(&mut self, signal: Signal) {
124 self.signals.push(signal);
125 }
126
127 fn append(&mut self, mut other: Self) {
129 self.signals.append(&mut other.signals);
130 }
131
132 pub fn signals(&self) -> &[Signal] {
134 &self.signals[..]
135 }
136}
137
138#[derive(Debug, PartialEq)]
140enum EraseType {
141 Character,
143 Word,
145 Line,
147}
148
149impl LineDiscipline {
150 pub fn termios(&self) -> &uapi::termios {
152 &self.termios
153 }
154
155 pub fn is_canon_enabled(&self) -> bool {
156 self.termios.has_local_flags(ICANON)
157 }
158
159 pub fn get_available_read_size(&self, is_main: bool) -> usize {
162 let queue = if is_main { self.output_queue() } else { self.input_queue() };
163 queue.readable_size()
164 }
165
166 pub fn set_termios(&mut self, termios: uapi::termios) -> PendingSignals {
168 let old_canon_enabled = self.is_canon_enabled();
169 self.termios = termios;
170 if old_canon_enabled && !self.is_canon_enabled() {
171 with_queue!(self.input_queue.on_canon_disabled(self))
172 } else {
173 PendingSignals::new()
174 }
175 }
176
177 pub fn main_close(&mut self) {
179 self.main_references = self.main_references.map(|v| v - 1);
180 }
181
182 pub fn main_open(&mut self) {
184 self.main_references = Some(self.main_references.unwrap_or(0) + 1);
185 }
186
187 pub fn is_main_closed(&self) -> bool {
188 matches!(self.main_references, Some(0))
189 }
190
191 pub fn main_query_events(&self) -> FdEvents {
193 if self.is_replica_closed() && self.output_queue().readable_size() == 0 {
194 return FdEvents::POLLOUT | FdEvents::POLLHUP;
195 }
196 self.output_queue().read_readiness() | self.input_queue().write_readiness()
197 }
198
199 pub fn main_read(&mut self, data: &mut dyn OutputBuffer) -> Result<usize, Errno> {
201 if self.is_replica_closed() && self.output_queue().readable_size() == 0 {
202 return error!(EIO);
203 }
204 with_queue!(self.output_queue.read(self, data))
205 }
206
207 pub fn main_write(
209 &mut self,
210 data: &mut dyn InputBuffer,
211 ) -> Result<(usize, PendingSignals), Errno> {
212 with_queue!(self.input_queue.write(self, data))
213 }
214
215 pub fn replica_close(&mut self) {
217 self.replica_references = self.replica_references.map(|v| v - 1);
218 }
219
220 pub fn replica_open(&mut self) {
222 self.replica_references = Some(self.replica_references.unwrap_or(0) + 1);
223 }
224
225 pub fn is_replica_closed(&self) -> bool {
226 matches!(self.replica_references, Some(0))
227 }
228
229 pub fn replica_query_events(&self) -> FdEvents {
231 if self.is_main_closed() {
232 return FdEvents::POLLIN | FdEvents::POLLOUT | FdEvents::POLLERR | FdEvents::POLLHUP;
233 }
234 self.input_queue().read_readiness() | self.output_queue().write_readiness()
235 }
236
237 pub fn replica_read(&mut self, data: &mut dyn OutputBuffer) -> Result<usize, Errno> {
239 if self.is_main_closed() {
240 return Ok(0);
241 }
242 with_queue!(self.input_queue.read(self, data))
243 }
244
245 pub fn replica_write(&mut self, data: &mut dyn InputBuffer) -> Result<usize, Errno> {
247 if self.is_main_closed() {
248 return error!(EIO);
249 }
250 if self.stopped && self.termios.has_input_flags(IXON) {
251 return error!(EAGAIN);
252 }
253 let (read_from_userspace, signals) = with_queue!(self.output_queue.write(self, data))?;
254 assert!(signals.signals().is_empty());
256 Ok(read_from_userspace)
257 }
258
259 fn input_queue(&self) -> &Queue {
261 self.input_queue.as_ref().unwrap()
262 }
263
264 fn output_queue(&self) -> &Queue {
266 self.output_queue.as_ref().unwrap()
267 }
268
269 fn handle_signals(&mut self, byte: RawByte) -> Option<Signal> {
271 if !self.termios.has_local_flags(ISIG) {
272 return None;
273 }
274 self.termios.signal(byte)
275 }
276
277 fn extend_echo_bytes(&self, target: &mut Vec<RawByte>, byte: RawByte) {
278 if self.termios.has_local_flags(ECHOCTL) {
279 if let Some(control_character_echo) = generate_control_character_echo(byte) {
280 target.extend(control_character_echo);
281 return;
282 }
283 }
284 target.push(byte);
285 }
286
287 fn transform(
288 &mut self,
289 is_input: bool,
290 queue: &mut Queue,
291 buffer: &[RawByte],
292 ) -> (usize, PendingSignals) {
293 if is_input {
294 self.transform_input(queue, buffer)
295 } else {
296 (self.transform_output(queue, buffer), PendingSignals::new())
297 }
298 }
299
300 fn transform_output(&mut self, queue: &mut Queue, original_buffer: &[RawByte]) -> usize {
301 let mut buffer = original_buffer;
302
303 if !self.termios.has_output_flags(OPOST) {
307 queue.read_queue.push_back(buffer.to_vec());
308 return buffer.len();
309 }
310
311 let mut return_value = 0;
312 while !buffer.is_empty() {
313 let size = compute_next_character_size(buffer, &self.termios);
314 let mut character_bytes = buffer[..size].to_vec();
315 return_value += size;
316 buffer = &buffer[size..];
317
318 if self.termios.has_output_flags(OLCUC) {
319 character_bytes[0].make_ascii_uppercase();
320 }
321 match character_bytes[0] {
322 b'\n' => {
323 if self.termios.has_output_flags(ONLRET) {
324 self.column = 0;
325 }
326 if self.termios.has_output_flags(ONLCR) {
327 queue.line_buffer.extend_from_slice(&[b'\r', b'\n']);
328 continue;
329 }
330 }
331 b'\r' => {
332 if self.termios.has_output_flags(ONOCR) && self.column == 0 {
333 continue;
334 }
335 if self.termios.has_output_flags(OCRNL) {
336 character_bytes[0] = b'\n';
337 if self.termios.has_output_flags(ONLRET) {
338 self.column = 0;
339 }
340 } else {
341 self.column = 0;
342 }
343 }
344 b'\t' => {
345 let spaces = SPACES_PER_TAB - self.column % SPACES_PER_TAB;
346 if self.termios.c_oflag & TABDLY == XTABS {
347 self.column += spaces;
348 queue.line_buffer.extend(std::iter::repeat(b' ').take(spaces));
349 continue;
350 }
351 self.column += spaces;
352 }
353 BACKSPACE_CHAR => {
354 if self.column > 0 {
355 self.column -= 1;
356 }
357 }
358 _ => {
359 self.column += 1;
360 }
361 }
362 queue.line_buffer.append(&mut character_bytes);
363 }
364 if !queue.line_buffer.is_empty() {
365 queue.flush_line_buffer();
366 }
367 return_value
368 }
369
370 fn transform_input(
371 &mut self,
372 queue: &mut Queue,
373 original_buffer: &[RawByte],
374 ) -> (usize, PendingSignals) {
375 let mut buffer = original_buffer;
376
377 let max_bytes = if self.termios.has_local_flags(ICANON) {
378 CANON_MAX_BYTES
379 } else {
380 NON_CANON_MAX_BYTES
381 };
382
383 let mut return_value = 0;
384 let mut signals = PendingSignals::new();
385 while !buffer.is_empty() && queue.line_buffer.len() < CANON_MAX_BYTES {
386 let size = compute_next_character_size(buffer, &self.termios);
387 let mut character_bytes = buffer[..size].to_vec();
388 if self.lnext {
391 self.lnext = false;
392 if self.termios.has_local_flags(ECHO) {
393 let mut echo_bytes = vec![];
394 self.extend_echo_bytes(&mut echo_bytes, character_bytes[0]);
395 signals.append(with_queue!(self.output_queue.write_bytes(self, &echo_bytes)));
396 }
397
398 queue.line_buffer.extend_from_slice(&character_bytes);
399 buffer = &buffer[size..];
400 return_value += size;
401 continue;
402 }
403
404 if self.termios.has_local_flags(IEXTEN) {
405 if character_bytes[0] == self.termios.c_cc[VLNEXT as usize]
407 && self.termios.c_cc[VLNEXT as usize] != DISABLED_CHAR
408 {
409 self.lnext = true;
410 if self.termios.has_local_flags(ECHO) && self.termios.has_local_flags(ECHOCTL) {
411 let echo_bytes = vec![b'^', BACKSPACE_CHAR];
412 signals
413 .append(with_queue!(self.output_queue.write_bytes(self, &echo_bytes)));
414 }
415 buffer = &buffer[size..];
416 return_value += size;
417 continue;
418 }
419 if character_bytes[0] == self.termios.c_cc[VREPRINT as usize]
421 && self.termios.c_cc[VREPRINT as usize] != DISABLED_CHAR
422 {
423 if self.termios.has_local_flags(ECHO) {
424 let mut echo_bytes = vec![];
425 self.extend_echo_bytes(&mut echo_bytes, character_bytes[0]);
426 echo_bytes.push(b'\n');
427 for byte in &queue.line_buffer {
428 self.extend_echo_bytes(&mut echo_bytes, *byte);
429 }
430 signals
431 .append(with_queue!(self.output_queue.write_bytes(self, &echo_bytes)));
432 }
433 buffer = &buffer[size..];
434 return_value += size;
435 continue;
436 }
437 }
438
439 if self.termios.has_input_flags(IUCLC) && self.termios.has_local_flags(IEXTEN) {
440 character_bytes[0].make_ascii_lowercase();
441 }
442
443 let mut signal_generated = false;
444 if let Some(signal) = self.handle_signals(character_bytes[0]) {
445 signals.add(signal);
446 signal_generated = true;
447 if !self.termios.has_local_flags(NOFLSH) {
448 queue.flush();
449 if let Some(ref mut output_queue) = self.output_queue {
450 output_queue.flush();
451 }
452 }
453 }
454
455 if self.termios.has_input_flags(IXON) {
457 if character_bytes[0] == self.termios.c_cc[VSTOP as usize] {
458 self.stopped = true;
459 buffer = &buffer[size..];
460 return_value += size;
461 continue;
462 }
463 if self.stopped
470 && (character_bytes[0] == self.termios.c_cc[VSTART as usize]
471 || self.termios.has_input_flags(IXANY))
472 {
473 self.stopped = false;
474 if character_bytes[0] == self.termios.c_cc[VSTART as usize] {
479 buffer = &buffer[size..];
480 return_value += size;
481 continue;
482 }
483 }
484 }
485
486 match character_bytes[0] {
487 b'\r' => {
488 if self.termios.has_input_flags(IGNCR) {
489 buffer = &buffer[size..];
490 return_value += size;
491 continue;
492 }
493 if self.termios.has_input_flags(ICRNL) {
494 character_bytes[0] = b'\n';
495 }
496 }
497 b'\n' => {
498 if self.termios.has_input_flags(INLCR) {
499 character_bytes[0] = b'\r'
500 }
501 }
502 _ => {}
503 }
504 if self.termios.has_local_flags(ICANON)
507 && queue.line_buffer.len() + size >= max_bytes
508 && !self.termios.is_terminating(&character_bytes)
509 {
510 buffer = &buffer[size..];
511 return_value += size;
512 continue;
513 }
514
515 if queue.line_buffer.len() + size > max_bytes {
516 break;
517 }
518
519 buffer = &buffer[size..];
520 return_value += size;
521
522 let first_byte = character_bytes[0];
523
524 if self.termios.has_local_flags(ICANON) && self.termios.is_eof(first_byte) {
526 if !queue.line_buffer.is_empty() {
527 queue.flush_line_buffer();
528 }
529 queue.read_queue.push_back(vec![]);
530 break;
531 }
532
533 let mut maybe_erase_span = None;
534 let mut erase_type = None;
535 if self.termios.has_local_flags(ICANON) {
536 if self.termios.is_erase(first_byte) {
537 maybe_erase_span =
538 Some(compute_last_character_span(&queue.line_buffer[..], &self.termios));
539 erase_type = Some(EraseType::Character);
540 } else if self.termios.is_werase(first_byte) {
541 maybe_erase_span =
542 Some(compute_last_word_span(&queue.line_buffer[..], &self.termios));
543 erase_type = Some(EraseType::Word);
544 }
545 if self.termios.is_kill(first_byte) {
546 maybe_erase_span =
547 Some(compute_last_line_span(&queue.line_buffer[..], &self.termios));
548 erase_type = Some(EraseType::Line);
549 }
550 }
551
552 let mut erased_bytes = Option::None;
553 if let Some(erase_span) = maybe_erase_span {
554 if erase_span.bytes == 0 {
555 continue;
556 }
557 if self.termios.has_local_flags(ECHOPRT) {
558 erased_bytes = Some(
559 queue.line_buffer[queue.line_buffer.len() - erase_span.bytes..].to_vec(),
560 );
561 }
562 queue.line_buffer.truncate(queue.line_buffer.len() - erase_span.bytes);
563 } else if !signal_generated {
564 queue.line_buffer.extend_from_slice(&character_bytes);
565 }
566
567 let mut echo_bytes = vec![];
569 if self.termios.has_local_flags(ECHO) {
570 if let Some(erase_span) = maybe_erase_span {
571 match erase_type {
572 Some(EraseType::Character) | Some(EraseType::Word) => {
573 if self.termios.has_local_flags(ECHOPRT) {
574 if let Some(bytes) = erased_bytes {
575 if !self.erasing {
576 echo_bytes.push(b'\\');
577 self.erasing = true;
578 }
579 for byte in bytes.iter().rev() {
580 self.extend_echo_bytes(&mut echo_bytes, *byte);
581 }
582 }
583 } else if self.termios.has_local_flags(ECHOE) {
584 echo_bytes = generate_erase_echo(&erase_span);
585 }
586 }
587 Some(EraseType::Line) => {
588 if self.termios.has_local_flags(ECHOKE) {
589 echo_bytes = generate_erase_echo(&erase_span);
590 } else if self.termios.has_local_flags(ECHOK) {
591 self.extend_echo_bytes(&mut echo_bytes, first_byte);
592 echo_bytes.push(b'\n');
593 }
594 }
595 None => {
596 unreachable!("Erase type should be Some when maybe_erase_span is Some")
597 }
598 }
599 if self.erasing && queue.line_buffer.is_empty() {
600 echo_bytes.push(b'/');
601 self.erasing = false;
602 }
603 } else {
604 if self.erasing && first_byte != b'\n' {
605 echo_bytes.push(b'/');
606 self.erasing = false;
607 }
608 }
609
610 let needs_normal_echo =
611 if maybe_erase_span.is_some() { echo_bytes.is_empty() } else { true };
612
613 if needs_normal_echo {
614 let mut char_echo = vec![];
615 if self.termios.has_local_flags(ECHOCTL) {
616 if let Some(control_character_echo) =
617 generate_control_character_echo(first_byte)
618 {
619 char_echo = control_character_echo;
620 }
621 }
622 if char_echo.is_empty() {
623 char_echo = character_bytes.clone();
624 }
625 echo_bytes.extend(char_echo);
626 }
627 } else if self.termios.has_local_flags(ECHONL) && first_byte == b'\n' {
628 echo_bytes.extend_from_slice(&character_bytes);
629 }
630
631 if !echo_bytes.is_empty() {
632 signals.append(with_queue!(self.output_queue.write_bytes(self, &echo_bytes)));
633 }
634
635 if self.termios.has_local_flags(ICANON) && self.termios.is_terminating(&character_bytes)
637 {
638 queue.flush_line_buffer();
639 }
640 }
641 if !self.termios.has_local_flags(ICANON) && !queue.line_buffer.is_empty() {
643 queue.flush_line_buffer();
644 }
645
646 (return_value, signals)
647 }
648}
649
650type RawByte = u8;
653
654#[derive(Debug, Default)]
655struct Queue {
656 read_queue: VecDeque<Vec<u8>>,
659
660 line_buffer: Vec<u8>,
664
665 wait_buffers: VecDeque<Vec<RawByte>>,
668
669 total_wait_buffer_length: usize,
671
672 is_input: bool,
674}
675
676impl Queue {
677 fn output_queue() -> Option<Self> {
678 Some(Queue { is_input: false, ..Default::default() })
679 }
680
681 fn input_queue() -> Option<Self> {
682 Some(Queue { is_input: true, ..Default::default() })
683 }
684
685 fn write_readiness(&self) -> FdEvents {
687 if self.total_wait_buffer_length < WAIT_BUFFER_MAX_BYTES {
688 FdEvents::POLLOUT
689 } else {
690 FdEvents::empty()
691 }
692 }
693
694 fn read_readiness(&self) -> FdEvents {
696 if !self.read_queue.is_empty() { FdEvents::POLLIN } else { FdEvents::empty() }
698 }
699
700 fn readable_size(&self) -> usize {
702 self.read_queue.iter().map(|v| v.len()).sum()
705 }
706
707 fn read(
709 &mut self,
710 terminal: &mut LineDiscipline,
711 data: &mut dyn OutputBuffer,
712 ) -> Result<usize, Errno> {
713 if self.read_queue.is_empty() {
714 return error!(EAGAIN);
715 }
716
717 let mut total_written = 0;
718 while let Some(mut packet) = self.read_queue.pop_front() {
719 if packet.is_empty() {
720 if total_written > 0 {
721 self.read_queue.push_front(packet);
724 }
725 break;
726 }
727
728 match data.write(&packet) {
729 Ok(written) => {
730 total_written += written;
731 if written < packet.len() {
732 let remaining = packet.split_off(written);
734 self.read_queue.push_front(remaining);
735 break;
737 }
738
739 if self.is_input && terminal.termios.has_local_flags(ICANON) {
741 break;
742 }
743 }
744 Err(e) => {
745 self.read_queue.push_front(packet);
747 if total_written > 0 {
748 return Ok(total_written);
750 }
751 return Err(e);
752 }
753 }
754 }
755
756 let signals = self.drain_waiting_buffer(terminal);
757 assert!(signals.signals().is_empty());
758 Ok(total_written)
759 }
760
761 fn write(
763 &mut self,
764 terminal: &mut LineDiscipline,
765 data: &mut dyn InputBuffer,
766 ) -> Result<(usize, PendingSignals), Errno> {
767 let room = WAIT_BUFFER_MAX_BYTES - self.total_wait_buffer_length;
768 let data_length = data.available();
769 if room == 0 && data_length > 0 {
770 return error!(EAGAIN);
771 }
772 let buffer = data.read_to_vec_exact(std::cmp::min(room, data_length))?;
773 let read_from_userspace = buffer.len();
774 let signals = self.push_to_waiting_buffer(terminal, buffer);
775 Ok((read_from_userspace, signals))
776 }
777
778 fn write_bytes(&mut self, terminal: &mut LineDiscipline, buffer: &[RawByte]) -> PendingSignals {
780 self.push_to_waiting_buffer(terminal, buffer.to_vec())
781 }
782
783 fn push_to_waiting_buffer(
785 &mut self,
786 terminal: &mut LineDiscipline,
787 buffer: Vec<RawByte>,
788 ) -> PendingSignals {
789 self.total_wait_buffer_length += buffer.len();
790 self.wait_buffers.push_back(buffer);
791 self.drain_waiting_buffer(terminal)
792 }
793
794 fn drain_waiting_buffer(&mut self, terminal: &mut LineDiscipline) -> PendingSignals {
796 let mut signals_to_return = PendingSignals::new();
797 while let Some(wait_buffer) = self.wait_buffers.pop_front() {
798 self.total_wait_buffer_length -= wait_buffer.len();
799 let (count, signals) = terminal.transform(self.is_input, self, &wait_buffer);
800 signals_to_return.append(signals);
801 if count != wait_buffer.len() {
802 let remaining = wait_buffer[count..].to_vec();
803 self.total_wait_buffer_length += remaining.len();
804 self.wait_buffers.push_front(remaining);
805 break;
806 }
807 }
808 signals_to_return
809 }
810
811 fn flush_line_buffer(&mut self) {
813 self.read_queue.push_back(std::mem::take(&mut self.line_buffer));
814 }
815
816 fn flush(&mut self) {
818 self.read_queue.clear();
819 self.line_buffer.clear();
820 self.wait_buffers.clear();
821 self.total_wait_buffer_length = 0;
822 }
823
824 fn on_canon_disabled(&mut self, terminal: &mut LineDiscipline) -> PendingSignals {
826 let signals = self.drain_waiting_buffer(terminal);
827 if !self.line_buffer.is_empty() {
828 self.flush_line_buffer();
829 }
830 signals
831 }
832}
833
834fn get_ascii(c: char) -> u8 {
838 let mut dest: [u8; 1] = [0];
839 c.encode_utf8(&mut dest);
840 dest[0]
841}
842
843fn get_control_character(c: char) -> cc_t {
845 get_ascii(c) - get_ascii('A') + 1
846}
847
848fn get_default_control_characters() -> [cc_t; 19usize] {
850 [
851 get_control_character('C'), get_control_character('\\'), get_ascii('\x7f'), get_control_character('U'), get_control_character('D'), 0, 1, 0, get_control_character('Q'), get_control_character('S'), get_control_character('Z'), 0, get_control_character('R'), get_control_character('O'), get_control_character('W'), get_control_character('V'), 0, 0, 0, ]
871}
872
873pub fn get_default_termios() -> uapi::termios {
875 uapi::termios {
876 c_iflag: uapi::ICRNL | uapi::IXON,
877 c_oflag: uapi::OPOST | uapi::ONLCR,
878 c_cflag: uapi::B38400 | uapi::CS8 | uapi::CREAD,
879 c_lflag: uapi::ISIG
880 | uapi::ICANON
881 | uapi::ECHO
882 | uapi::ECHOE
883 | uapi::ECHOK
884 | uapi::ECHOCTL
885 | uapi::ECHOKE
886 | uapi::IEXTEN,
887 c_line: 0,
888 c_cc: get_default_control_characters(),
889 }
890}
891
892trait TermIOS {
894 fn has_input_flags(&self, flags: tcflag_t) -> bool;
895 fn has_output_flags(&self, flags: tcflag_t) -> bool;
896 fn has_local_flags(&self, flags: tcflag_t) -> bool;
897 fn is_eof(&self, c: RawByte) -> bool;
898 fn is_erase(&self, c: RawByte) -> bool;
899 fn is_werase(&self, c: RawByte) -> bool;
900 fn is_kill(&self, c: RawByte) -> bool;
901 fn is_terminating(&self, character_bytes: &[RawByte]) -> bool;
902 fn signal(&self, c: RawByte) -> Option<Signal>;
903}
904
905impl TermIOS for uapi::termios {
906 fn has_input_flags(&self, flags: tcflag_t) -> bool {
907 self.c_iflag & flags == flags
908 }
909 fn has_output_flags(&self, flags: tcflag_t) -> bool {
910 self.c_oflag & flags == flags
911 }
912 fn has_local_flags(&self, flags: tcflag_t) -> bool {
913 self.c_lflag & flags == flags
914 }
915 fn is_eof(&self, c: RawByte) -> bool {
916 c == self.c_cc[VEOF as usize] && self.c_cc[VEOF as usize] != DISABLED_CHAR
917 }
918 fn is_erase(&self, c: RawByte) -> bool {
919 c == self.c_cc[VERASE as usize] && self.c_cc[VERASE as usize] != DISABLED_CHAR
920 }
921 fn is_werase(&self, c: RawByte) -> bool {
922 c == self.c_cc[VWERASE as usize]
923 && self.c_cc[VWERASE as usize] != DISABLED_CHAR
924 && self.has_local_flags(IEXTEN)
925 }
926 fn is_kill(&self, c: RawByte) -> bool {
927 c == self.c_cc[VKILL as usize] && self.c_cc[VKILL as usize] != DISABLED_CHAR
928 }
929 fn is_terminating(&self, character_bytes: &[RawByte]) -> bool {
930 if character_bytes.len() != 1 {
932 return false;
933 }
934 let c = character_bytes[0];
935
936 if self.is_eof(c) {
938 return true;
939 }
940
941 if c == DISABLED_CHAR {
942 return false;
943 }
944 if c == b'\n' || c == self.c_cc[VEOL as usize] {
945 return true;
946 }
947 if c == self.c_cc[VEOL2 as usize] {
948 return self.has_local_flags(IEXTEN);
949 }
950 false
951 }
952 fn signal(&self, c: RawByte) -> Option<Signal> {
953 if c == DISABLED_CHAR {
954 return None;
955 }
956 if c == self.c_cc[VINTR as usize] {
957 return Some(SIGINT);
958 }
959 if c == self.c_cc[VQUIT as usize] {
960 return Some(SIGQUIT);
961 }
962 if c == self.c_cc[VSUSP as usize] {
963 return Some(SIGSTOP);
964 }
965 None
966 }
967}
968
969fn compute_next_character_size(buffer: &[RawByte], termios: &uapi::termios) -> usize {
970 if !termios.has_input_flags(IUTF8) {
971 return 1;
972 }
973
974 #[derive(Default)]
975 struct Receiver {
976 done: Option<bool>,
977 }
978
979 impl utf8parse::Receiver for Receiver {
980 fn codepoint(&mut self, _c: char) {
981 self.done = Some(true);
982 }
983 fn invalid_sequence(&mut self) {
984 self.done = Some(false);
985 }
986 }
987
988 let mut byte_count = 0;
989 let mut receiver = Receiver::default();
990 let mut parser = utf8parse::Parser::new();
991 while receiver.done.is_none() && byte_count < buffer.len() {
992 parser.advance(&mut receiver, buffer[byte_count]);
993 byte_count += 1;
994 }
995 if receiver.done == Some(true) { byte_count } else { 1 }
996}
997
998fn is_ascii(c: RawByte) -> bool {
999 c & 0x80 == 0
1000}
1001
1002fn is_utf8_start(c: RawByte) -> bool {
1003 c & 0xC0 == 0xC0
1004}
1005
1006fn generate_erase_echo(erase_span: &BufferSpan) -> Vec<RawByte> {
1007 let erase_echo = [BACKSPACE_CHAR, b' ', BACKSPACE_CHAR];
1008 erase_echo.iter().cycle().take(erase_echo.len() * erase_span.characters).map(|c| *c).collect()
1009}
1010
1011fn generate_control_character_echo(c: RawByte) -> Option<Vec<RawByte>> {
1012 if matches!(c, 0..=0x8 | 0xB..=0xC | 0xE..=0x1F) {
1013 Some(vec![b'^', c + CONTROL_OFFSET])
1014 } else {
1015 None
1016 }
1017}
1018
1019#[derive(Default, Debug, Clone, Copy)]
1020struct BufferSpan {
1021 bytes: usize,
1022 characters: usize,
1023}
1024
1025impl std::ops::AddAssign<Self> for BufferSpan {
1026 fn add_assign(&mut self, rhs: Self) {
1027 self.bytes += rhs.bytes;
1028 self.characters += rhs.characters;
1029 }
1030}
1031
1032fn compute_last_character_span(buffer: &[RawByte], termios: &uapi::termios) -> BufferSpan {
1033 if buffer.is_empty() {
1034 return BufferSpan::default();
1035 }
1036 if termios.has_input_flags(IUTF8) {
1037 let mut bytes = 0;
1038 for c in buffer.iter().rev() {
1039 bytes += 1;
1040 if is_ascii(*c) || is_utf8_start(*c) {
1041 return BufferSpan { bytes, characters: 1 };
1042 }
1043 }
1044 BufferSpan::default()
1045 } else {
1046 BufferSpan { bytes: 1, characters: 1 }
1047 }
1048}
1049
1050fn compute_last_word_span(buffer: &[RawByte], termios: &uapi::termios) -> BufferSpan {
1051 fn is_whitespace(c: RawByte) -> bool {
1052 c == b' ' || c == b'\t'
1053 }
1054
1055 let mut in_word = false;
1056 let mut word_span = BufferSpan::default();
1057 let mut remaining = buffer.len();
1058 loop {
1059 let span = compute_last_character_span(&buffer[..remaining], termios);
1060 if span.bytes == 0 {
1061 break;
1062 }
1063 if span.bytes == 1 {
1064 let c = buffer[remaining - 1];
1065 if in_word {
1066 if is_whitespace(c) {
1067 break;
1068 }
1069 } else {
1070 if !is_whitespace(c) {
1071 in_word = true;
1072 }
1073 }
1074 }
1075 remaining -= span.bytes;
1076 word_span += span;
1077 }
1078
1079 word_span
1080}
1081
1082fn compute_last_line_span(buffer: &[RawByte], termios: &uapi::termios) -> BufferSpan {
1083 let mut line_span = BufferSpan::default();
1084 let mut remaining = buffer.len();
1085
1086 loop {
1087 let span = compute_last_character_span(&buffer[..remaining], termios);
1088 if span.bytes == 0 {
1089 break;
1090 }
1091 if span.bytes == 1 {
1092 let c = buffer[remaining - 1];
1093 if c == b'\n' {
1094 break;
1095 }
1096 }
1097 remaining -= span.bytes;
1098 line_span += span;
1099 }
1100
1101 line_span
1102}
1103
1104#[cfg(test)]
1105mod tests {
1106 use super::*;
1107
1108 #[::fuchsia::test]
1109 fn test_ascii_conversion() {
1110 assert_eq!(get_ascii(' '), 32);
1111 }
1112
1113 #[::fuchsia::test]
1114 fn test_control_character() {
1115 assert_eq!(get_control_character('C'), 3);
1116 }
1117
1118 #[::fuchsia::test]
1119 fn test_compute_next_character_size_non_utf8() {
1120 let termios = get_default_termios();
1121 for i in 0..=255 {
1122 let array: &[u8] = &[i, 0xa9, 0];
1123 assert_eq!(compute_next_character_size(array, &termios), 1);
1124 }
1125 }
1126
1127 #[::fuchsia::test]
1128 fn test_compute_next_character_size_utf8() {
1129 let mut termios = get_default_termios();
1130 termios.c_iflag |= IUTF8;
1131 for i in 0..128 {
1132 let array: &[RawByte] = &[i, 0xa9, 0];
1133 assert_eq!(compute_next_character_size(array, &termios), 1);
1134 }
1135 let array: &[RawByte] = &[0xc2, 0xa9, 0];
1136 assert_eq!(compute_next_character_size(array, &termios), 2);
1137 let array: &[RawByte] = &[0xc2, 255, 0];
1138 assert_eq!(compute_next_character_size(array, &termios), 1);
1139 }
1140
1141 #[::fuchsia::test]
1142 fn test_signal_handling_with_disabled_chars() {
1143 let mut termios = get_default_termios();
1144 termios.c_cc[VINTR as usize] = DISABLED_CHAR;
1145 termios.c_cc[VQUIT as usize] = DISABLED_CHAR;
1146 termios.c_cc[VSUSP as usize] = DISABLED_CHAR;
1147
1148 assert_eq!(termios.signal(0), None);
1149 assert_eq!(termios.signal(3), None); assert_eq!(termios.signal(28), None); assert_eq!(termios.signal(26), None); }
1153}
1154
1155pub mod testing;