Skip to content

Commit f96b0ee

Browse files
stty: matches GNU in what control character mappings are allowed
1 parent 3fc98a9 commit f96b0ee

File tree

1 file changed

+48
-22
lines changed

1 file changed

+48
-22
lines changed

src/uu/stty/src/stty.rs

Lines changed: 48 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,11 @@ enum Device {
104104
Stdout(Stdout),
105105
}
106106

107+
enum ControlCharMappingError {
108+
IntOutOfRange,
109+
MultipleChars,
110+
}
111+
107112
impl AsFd for Device {
108113
fn as_fd(&self) -> BorrowedFd<'_> {
109114
match self {
@@ -213,13 +218,22 @@ fn stty(opts: &Options) -> UResult<()> {
213218
format!("missing argument to '{setting}'"),
214219
));
215220
};
216-
if let ControlFlow::Break(false) =
217-
apply_char_mapping(&mut termios, char_index, new_cc)
218-
{
219-
return Err(USimpleError::new(
220-
1,
221-
format!("invalid mapping '{setting}' => '{new_cc}'"),
222-
));
221+
match apply_char_mapping(&mut termios, char_index, new_cc) {
222+
Ok(_) => {}
223+
Err(e) => match e {
224+
ControlCharMappingError::IntOutOfRange => {
225+
return Err(USimpleError::new(
226+
1,
227+
format!("invalid integer argument: '{new_cc}': Numerical result out of range"),
228+
));
229+
}
230+
ControlCharMappingError::MultipleChars => {
231+
return Err(USimpleError::new(
232+
1,
233+
format!("invalid integer argument: '{new_cc}'"),
234+
));
235+
}
236+
},
223237
}
224238
} else if let ControlFlow::Break(false) = apply_setting(&mut termios, setting) {
225239
return Err(USimpleError::new(
@@ -492,12 +506,14 @@ fn apply_char_mapping(
492506
termios: &mut Termios,
493507
control_char_index: SpecialCharacterIndices,
494508
new_val: &str,
495-
) -> ControlFlow<bool> {
496-
if let Some(val) = string_to_control_char(new_val) {
497-
termios.control_chars[control_char_index as usize] = val;
498-
return ControlFlow::Break(true);
509+
) -> Result<(), ControlCharMappingError> {
510+
match string_to_control_char(new_val) {
511+
Ok(val) => {
512+
termios.control_chars[control_char_index as usize] = val;
513+
Ok(())
514+
}
515+
Err(e) => Err(e),
499516
}
500-
ControlFlow::Break(false)
501517
}
502518

503519
// GNU stty defines some valid values for the control character mappings
@@ -509,33 +525,43 @@ fn apply_char_mapping(
509525
// 3. Disabling the control character: '^-' or 'undef'
510526
//
511527
// This function returns the ascii value of valid control chars, or None if the input is invalid
512-
fn string_to_control_char(s: &str) -> Option<u8> {
528+
fn string_to_control_char(s: &str) -> Result<u8, ControlCharMappingError> {
513529
if s == "undef" || s == "^-" {
514-
return Some(0);
530+
return Ok(0);
515531
}
516532

533+
// check if the number is greater than 255, return ControlCharMappingError::IntOutOfRange
517534
// try to parse integer (hex, octal, or decimal)
535+
let mut ascii_num: Option<u32> = None;
518536
if let Some(hex) = s.strip_prefix("0x") {
519-
return u8::from_str_radix(hex, 16).ok();
537+
ascii_num = u32::from_str_radix(hex, 16).ok();
520538
} else if let Some(octal) = s.strip_prefix("0") {
521-
return u8::from_str_radix(octal, 8).ok();
522-
} else if let Ok(decimal) = s.parse::<u8>() {
523-
return Some(decimal);
539+
ascii_num = u32::from_str_radix(octal, 8).ok();
540+
} else if let Ok(decimal) = s.parse::<u32>() {
541+
ascii_num = Some(decimal);
524542
}
525543

544+
if let Some(val) = ascii_num {
545+
if val > 255 {
546+
return Err(ControlCharMappingError::IntOutOfRange);
547+
} else {
548+
return Ok(val as u8);
549+
}
550+
}
526551
// try to parse ^<char> or just <char>
527552
let mut chars = s.chars();
528553
match (chars.next(), chars.next()) {
529554
(Some('^'), Some(c)) => {
530555
// special case: ascii value of '^?' is greater than '?'
531556
if c == '?' {
532-
return Some(ASCII_DEL);
557+
return Ok(ASCII_DEL);
533558
}
534559
// subract by '@' to turn the char into the ascii value of '^<char>'
535-
Some((c.to_ascii_uppercase() as u8).wrapping_sub(b'@'))
560+
Ok((c.to_ascii_uppercase() as u8).wrapping_sub(b'@'))
536561
}
537-
(Some(c), _) => Some(c as u8),
538-
_ => None,
562+
(Some(c), None) => Ok(c as u8),
563+
(Some(_), Some(_)) => Err(ControlCharMappingError::MultipleChars),
564+
_ => unreachable!("No arguments provided: must have been caught earlier"),
539565
}
540566
}
541567

0 commit comments

Comments
 (0)