Skip to content

Commit 2da271f

Browse files
willshuttleworthsylvestre
authored andcommitted
stty: setting control chars to undefined (disabling them) is implemented
1 parent e1c9f2a commit 2da271f

File tree

1 file changed

+41
-19
lines changed

1 file changed

+41
-19
lines changed

src/uu/stty/src/stty.rs

Lines changed: 41 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -203,27 +203,24 @@ fn stty(opts: &Options) -> UResult<()> {
203203
let mut termios = tcgetattr(opts.file.as_fd()).expect("Could not get terminal attributes");
204204

205205
if let Some(settings) = &opts.settings {
206-
let mut settings_iter = settings.into_iter();
206+
let mut settings_iter = settings.iter();
207207
while let Some(setting) = settings_iter.next() {
208-
if is_control_char(setting) {
209-
let new_cc = match settings_iter.next() {
210-
Some(cc) => cc,
211-
None => {
212-
return Err(USimpleError::new(
213-
1,
214-
format!("no mapping specified for '{setting}'"),
215-
));
216-
}
208+
if let Some(char_index) = is_control_char(setting) {
209+
let Some(new_cc) = settings_iter.next() else {
210+
return Err(USimpleError::new(
211+
1,
212+
format!("no mapping specified for '{setting}'"),
213+
));
217214
};
218-
if let ControlFlow::Break(false) = apply_char_mapping(&mut termios, setting, new_cc)
215+
if let ControlFlow::Break(false) =
216+
apply_char_mapping(&mut termios, setting, char_index, new_cc)
219217
{
220218
return Err(USimpleError::new(
221219
1,
222220
format!("invalid mapping '{setting}' => '{new_cc}'"),
223221
));
224222
}
225-
}
226-
else if let ControlFlow::Break(false) = apply_setting(&mut termios, setting) {
223+
} else if let ControlFlow::Break(false) = apply_setting(&mut termios, setting) {
227224
return Err(USimpleError::new(
228225
1,
229226
format!("invalid argument '{setting}'"),
@@ -293,13 +290,13 @@ fn print_terminal_size(termios: &Termios, opts: &Options) -> nix::Result<()> {
293290
Ok(())
294291
}
295292

296-
fn is_control_char(option: &str) -> bool {
293+
fn is_control_char(option: &str) -> Option<SpecialCharacterIndices> {
297294
for cc in CONTROL_CHARS {
298295
if option == cc.0 {
299-
return true;
296+
return Some(cc.1);
300297
}
301298
}
302-
false
299+
None
303300
}
304301

305302
fn control_char_to_string(cc: nix::libc::cc_t) -> nix::Result<String> {
@@ -490,9 +487,34 @@ fn apply_baud_rate_flag(termios: &mut Termios, input: &str) -> ControlFlow<bool>
490487
ControlFlow::Continue(())
491488
}
492489

493-
fn apply_char_mapping(termios: &mut Termios, cc: &str, new_cc: &str) -> ControlFlow<bool> {
494-
println!("{cc} {new_cc}");
495-
ControlFlow::Break(true)
490+
fn apply_char_mapping(
491+
termios: &mut Termios,
492+
cc: &str,
493+
control_char_index: SpecialCharacterIndices,
494+
new_cc: &str,
495+
) -> ControlFlow<bool> {
496+
if let Some(val) = string_to_control_char(new_cc) {
497+
termios.control_chars[control_char_index as usize] = val;
498+
return ControlFlow::Break(true);
499+
}
500+
ControlFlow::Break(false)
501+
}
502+
503+
// GNU stty defines some valid values for the control character mappings
504+
// 1. Standard character, can be a a single char (ie 'C') or hat notation (ie '^C')
505+
// 2. Integer
506+
// a. hexadecimal, prefixed by '0x'
507+
// b. octal, prefixed by '0'
508+
// c. decimal, no prefix
509+
// 3. Disabling the control character: '^-' or 'undef'
510+
//
511+
// This function returns the ascii value of the given char, or None if the input cannot be parsed
512+
fn string_to_control_char(s: &str) -> Option<u8> {
513+
// try to parse int, then char
514+
if s == "undef" || s == "^-" {
515+
return Some(0);
516+
}
517+
None
496518
}
497519

498520
pub fn uu_app() -> Command {

0 commit comments

Comments
 (0)