Add termios struct for flags (default taken from stty sane/cooked)

This commit is contained in:
pjht 2024-09-16 15:30:02 -05:00
parent e0b403ef7a
commit e5144a8e6e
Signed by: pjht
GPG Key ID: CA239FC6934E6F3A
3 changed files with 259 additions and 5 deletions

2
Cargo.lock generated
View File

@ -183,7 +183,7 @@ dependencies = [
]
[[package]]
name = "pty_driver"
name = "pty_server"
version = "0.1.0"
dependencies = [
"dev_driver_rpc",

View File

@ -1,3 +1,5 @@
mod termios;
use std::{
borrow::Cow,
collections::HashMap,
@ -8,10 +10,12 @@ use std::{
use parking_lot::{Mutex, RwLock};
use slab::Slab;
use termios::Termios;
struct Pty {
input_buffer: Mutex<Vec<u8>>,
output_buffer: Mutex<Vec<u8>>,
termios: Termios,
}
impl Pty {
@ -19,6 +23,7 @@ impl Pty {
Pty {
input_buffer: Mutex::new(Vec::new()),
output_buffer: Mutex::new(Vec::new()),
termios: Termios::default(),
}
}
@ -31,16 +36,41 @@ impl Pty {
}
fn write_master(&self, data: &[u8]) -> Result<(), ()> {
if !self.termios.cflags.cread {
return Ok(())
}
let mut input_buffer = self.input_buffer.lock();
let mut output_buffer = self.output_buffer.lock();
for &byte in data {
output_buffer.push(byte);
if byte == 8 {
for &(mut byte) in data {
if self.termios.iflags.istrip {
byte &= 0x7F;
}
if byte == b'\r' && self.termios.iflags.igncr {
continue;
} else if byte == b'\r' && self.termios.iflags.icrnl {
byte = b'\n';
} else if byte == b'\n' && self.termios.iflags.inlcr {
byte = b'\r';
}
if byte as char == self.termios.verase && self.termios.lflags.icanon {
if self.termios.lflags.echoe {
output_buffer.push(byte);
}
if input_buffer.last() != Some(&b'\n') {
input_buffer.pop();
}
} else if byte as char == self.termios.vkill && self.termios.lflags.icanon {
while input_buffer.last().is_some() && input_buffer.last() != Some(&b'\n') {
if self.termios.lflags.echok {
output_buffer.push(8);
}
input_buffer.pop();
}
} else {
input_buffer.push(byte);
if self.termios.lflags.echo || (byte == b'\n' && self.termios.lflags.echonl) {
output_buffer.push(byte);
}
}
}
Ok(())
@ -60,7 +90,19 @@ impl Pty {
}
fn write_slave(&self, data: &[u8]) -> Result<(), ()> {
self.output_buffer.lock().extend(data);
let mut output_buffer = self.output_buffer.lock();
for &byte in data {
if self.termios.oflags.opost {
if byte == b'\n' && self.termios.oflags.onlcr {
output_buffer.push(b'\r');
output_buffer.push(b'\n');
} else if byte == b'\r' && self.termios.oflags.ocrnl {
output_buffer.push(b'\n');
} else {
output_buffer.push(byte);
}
}
}
Ok(())
}
}

212
src/termios.rs Normal file
View File

@ -0,0 +1,212 @@
#[allow(unused)]
pub struct Iflags {
pub brkint: bool,
pub icrnl: bool,
pub ignbrk: bool,
pub igncr: bool,
pub ignpar: bool,
pub inlcr: bool,
pub inpck: bool,
pub istrip: bool,
pub ixany: bool,
pub ixoff: bool,
pub ixon: bool,
pub parmark: bool,
}
impl Default for Iflags {
fn default() -> Self {
Self {
brkint: false,
icrnl: true,
ignbrk: false,
igncr: false,
ignpar: true,
inlcr: false,
inpck: true,
istrip: false,
ixany: false,
ixoff: false,
ixon: false,
parmark: false,
}
}
}
#[allow(unused)]
pub struct Oflags {
pub opost: bool,
pub onlcr: bool,
pub ocrnl: bool,
pub onocr: bool,
pub onlret: bool,
pub ofdel: bool,
pub nldly: NlDelay,
pub crdly: CrDelay,
pub tabdly: TabDelay,
pub bsdly: BsDelay,
pub vtdly: VtDelay,
pub ffdly: FfDelay,
}
impl Default for Oflags {
fn default() -> Self {
Self {
opost: true,
onlcr: true,
ocrnl: false,
onocr: false,
onlret: false,
ofdel: false,
nldly: NlDelay::Nl0,
crdly: CrDelay::Cr0,
tabdly: TabDelay::Tab0,
bsdly: BsDelay::Bs0,
vtdly: VtDelay::Vt0,
ffdly: FfDelay::Ff0,
}
}
}
#[allow(unused)]
pub enum NlDelay {
Nl0,
Nl1,
}
#[allow(unused)]
pub enum CrDelay {
Cr0,
Cr1,
Cr2,
Cr3,
}
#[allow(unused)]
pub enum TabDelay {
Tab0,
Tab1,
Tab2,
Tab3,
}
#[allow(unused)]
pub enum BsDelay {
Bs0,
Bs1,
}
#[allow(unused)]
pub enum VtDelay {
Vt0,
Vt1,
}
#[allow(unused)]
pub enum FfDelay {
Ff0,
Ff1,
}
#[allow(unused)]
pub struct Cflags {
pub csize: CharSize,
pub cstopb: bool,
pub cread: bool,
pub parenb: bool,
pub parodd: bool,
pub hupcl: bool,
pub clocal: bool,
}
impl Default for Cflags {
fn default() -> Self {
Self {
csize: CharSize::Cs8,
cstopb: false,
cread: true,
parenb: false,
parodd: false,
hupcl: true,
clocal: false,
}
}
}
#[allow(unused)]
pub enum CharSize {
Cs5,
Cs6,
Cs7,
Cs8,
}
#[allow(unused)]
pub struct Lflags {
pub echo: bool,
pub echoe: bool,
pub echok: bool,
pub echonl: bool,
pub icanon: bool,
pub iexten: bool,
pub isig: bool,
pub noflsh: bool,
pub tostop: bool,
}
impl Default for Lflags {
fn default() -> Self {
Self {
echo: true,
echoe: true,
echok: true,
echonl: false,
icanon: true,
iexten: true,
isig: true,
noflsh: false,
tostop: false,
}
}
}
#[allow(unused)]
pub struct Termios {
pub iflags: Iflags,
pub oflags: Oflags,
pub cflags: Cflags,
pub lflags: Lflags,
pub veof: char,
pub veol: char,
pub verase: char,
pub vintr: char,
pub vkill: char,
pub vmin: u32,
pub vquit: char,
pub vstart: char,
pub vstop: char,
pub vsusp: char,
pub vtime: u32,
}
impl Default for Termios {
fn default() -> Self {
Self {
iflags: Iflags::default(),
oflags: Oflags::default(),
cflags: Cflags::default(),
lflags: Lflags::default(),
veof: '\u{4}', //ctrl-D (EOT)
veol: '\n',
verase: '\u{8}', //ctrl-H (BS)
vintr: '\u{3}', //ctrl-C (ETX)
vkill: '\u{15}', //ctrl-U (NAK)
vmin: 0,
vquit: '\u{1C}', //ctrl-\
vstart: '\u{11}', // ctrl-S (XONN)
vstop: '\u{13}', // ctrl-Q (XOFF)
vsusp: '\u{1A}', // ctrl-Z (SUB)
vtime: 0,
}
}
}