stty: support sane settings

This commit is contained in:
yuankunzhang 2025-06-28 04:05:47 +00:00
parent 1bb7930a08
commit a8fe603284
2 changed files with 60 additions and 1 deletions

View file

@ -47,6 +47,22 @@ use flags::{CONTROL_CHARS, CONTROL_FLAGS, INPUT_FLAGS, LOCAL_FLAGS, OUTPUT_FLAGS
const ASCII_DEL: u8 = 127;
// Sane defaults for control characters.
const SANE_CONTROL_CHARS: [(S, u8); 12] = [
(S::VINTR, 3), // ^C
(S::VQUIT, 28), // ^\
(S::VERASE, 127), // DEL
(S::VKILL, 21), // ^U
(S::VEOF, 4), // ^D
(S::VSTART, 17), // ^Q
(S::VSTOP, 19), // ^S
(S::VSUSP, 26), // ^Z
(S::VREPRINT, 18), // ^R
(S::VWERASE, 23), // ^W
(S::VLNEXT, 22), // ^V
(S::VDISCARD, 15), // ^O
];
#[derive(Clone, Copy, Debug)]
pub struct Flag<T> {
name: &'static str,
@ -694,7 +710,21 @@ fn control_char_to_string(cc: nix::libc::cc_t) -> nix::Result<String> {
fn print_control_chars(termios: &Termios, opts: &Options) -> nix::Result<()> {
if !opts.all {
// TODO: this branch should print values that differ from defaults
// Print only control chars that differ from sane defaults
let mut printed = false;
for (text, cc_index) in CONTROL_CHARS {
let current_val = termios.control_chars[*cc_index as usize];
let sane_val = get_sane_control_char(*cc_index);
if current_val != sane_val {
print!("{text} = {}; ", control_char_to_string(current_val)?);
printed = true;
}
}
if printed {
println!();
}
return Ok(());
}
@ -1025,6 +1055,24 @@ fn combo_to_flags(combo: &str) -> Vec<ArgOptions> {
flags
}
fn get_sane_control_char(cc_index: S) -> u8 {
for (sane_index, sane_val) in SANE_CONTROL_CHARS {
if sane_index == cc_index {
return sane_val;
}
}
// Default values for control chars not in the sane list
match cc_index {
S::VEOL => 0,
S::VEOL2 => 0,
S::VMIN => 1,
S::VTIME => 0,
#[cfg(target_os = "linux")]
S::VSWTC => 0,
_ => 0,
}
}
pub fn uu_app() -> Command {
Command::new(uucore::util_name())
.version(uucore::crate_version!())

View file

@ -30,6 +30,17 @@ fn print_all() {
}
}
#[test]
#[ignore = "Fails because cargo test does not run in a tty"]
fn sane_settings() {
new_ucmd!().args(&["intr", "^A"]).succeeds();
new_ucmd!().succeeds().stdout_contains("intr = ^A");
new_ucmd!()
.args(&["sane"])
.succeeds()
.stdout_str_check(|s| !s.contains("intr = ^A"));
}
#[test]
fn save_and_setting() {
new_ucmd!()