Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
270 changes: 124 additions & 146 deletions src/uu/stty/src/stty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ use std::num::IntErrorKind;
use std::os::fd::{AsFd, BorrowedFd};
use std::os::unix::fs::OpenOptionsExt;
use std::os::unix::io::{AsRawFd, RawFd};
use uucore::error::{UResult, USimpleError};
use uucore::error::{UError, UResult, USimpleError};
use uucore::format_usage;
use uucore::locale::{get_message, get_message_with_args};

Expand Down Expand Up @@ -270,37 +270,9 @@ fn stty(opts: &Options) -> UResult<()> {

if let Some(args) = &opts.settings {
let mut args_iter = args.iter();
// iterate over args: skip to next arg if current one is a control char
while let Some(&arg) = args_iter.next() {
// control char
if let Some(char_index) = cc_to_index(arg) {
if let Some(mapping) = args_iter.next() {
let cc_mapping = string_to_control_char(mapping).map_err(|e| {
let message = match e {
ControlCharMappingError::IntOutOfRange(val) => get_message_with_args(
"stty-error-invalid-integer-argument-value-too-large",
HashMap::from([("value".to_string(), format!("'{val}'"))]),
),
ControlCharMappingError::MultipleChars(val) => get_message_with_args(
"stty-error-invalid-integer-argument",
HashMap::from([("value".to_string(), format!("'{val}'"))]),
),
};
USimpleError::new(1, message)
})?;
valid_args.push(ArgOptions::Mapping((char_index, cc_mapping)));
} else {
return Err(USimpleError::new(
1,
get_message_with_args(
"stty-error-missing-argument",
HashMap::from([("arg".to_string(), (*arg).to_string())]),
),
));
}
// ispeed/ospeed baud rate setting
} else if arg == "ispeed" || arg == "ospeed" {
match args_iter.next() {
match arg {
"ispeed" | "ospeed" => match args_iter.next() {
Some(speed) => {
if let Some(baud_flag) = string_to_baud(speed) {
valid_args.push(ArgOptions::Flags(baud_flag));
Expand All @@ -318,149 +290,125 @@ fn stty(opts: &Options) -> UResult<()> {
}
}
None => {
return Err(USimpleError::new(
1,
get_message_with_args(
"stty-error-missing-argument",
HashMap::from([("arg".to_string(), (*arg).to_string())]),
),
));
return missing_arg(arg);
}
}
} else if arg == "line" {
match args_iter.next() {
},
"line" => match args_iter.next() {
Some(line) => match parse_u8_or_err(line) {
Ok(n) => valid_args.push(ArgOptions::Special(SpecialSetting::Line(n))),
Err(e) => return Err(USimpleError::new(1, e)),
},
None => {
return Err(USimpleError::new(
1,
get_message_with_args(
"stty-error-missing-argument",
HashMap::from([("arg".to_string(), arg.to_string())]),
),
));
return missing_arg(arg);
}
}
} else if arg == "min" {
match args_iter.next() {
},
"min" => match args_iter.next() {
Some(min) => match parse_u8_or_err(min) {
Ok(n) => {
valid_args.push(ArgOptions::Mapping((S::VMIN, n)));
}
Err(e) => return Err(USimpleError::new(1, e)),
},
None => {
return Err(USimpleError::new(
1,
get_message_with_args(
"stty-error-missing-argument",
HashMap::from([("arg".to_string(), arg.to_string())]),
),
));
return missing_arg(arg);
}
}
} else if arg == "time" {
match args_iter.next() {
},
"time" => match args_iter.next() {
Some(time) => match parse_u8_or_err(time) {
Ok(n) => valid_args.push(ArgOptions::Mapping((S::VTIME, n))),
Err(e) => return Err(USimpleError::new(1, e)),
},
None => {
return Err(USimpleError::new(
1,
get_message_with_args(
"stty-error-missing-argument",
HashMap::from([("arg".to_string(), arg.to_string())]),
),
));
return missing_arg(arg);
}
},
"rows" => {
if let Some(rows) = args_iter.next() {
if let Some(n) = parse_rows_cols(rows) {
valid_args.push(ArgOptions::Special(SpecialSetting::Rows(n)));
} else {
return invalid_integer_arg(rows);
}
} else {
return missing_arg(arg);
}
}
// baud rate setting
} else if let Some(baud_flag) = string_to_baud(arg) {
valid_args.push(ArgOptions::Flags(baud_flag));
// non control char flag
} else if let Some(flag) = string_to_flag(arg) {
let remove_group = match flag {
AllFlags::Baud(_) => false,
AllFlags::ControlFlags((flag, remove)) => check_flag_group(flag, remove),
AllFlags::InputFlags((flag, remove)) => check_flag_group(flag, remove),
AllFlags::LocalFlags((flag, remove)) => check_flag_group(flag, remove),
AllFlags::OutputFlags((flag, remove)) => check_flag_group(flag, remove),
};
if remove_group {
return Err(USimpleError::new(
1,
get_message_with_args(
"stty-error-invalid-argument",
HashMap::from([("arg".to_string(), (*arg).to_string())]),
),
));
}
valid_args.push(flag.into());
// combination setting
} else if let Some(combo) = string_to_combo(arg) {
valid_args.append(&mut combo_to_flags(combo));
} else if arg == "rows" {
if let Some(rows) = args_iter.next() {
if let Some(n) = parse_rows_cols(rows) {
valid_args.push(ArgOptions::Special(SpecialSetting::Rows(n)));
"columns" | "cols" => {
if let Some(cols) = args_iter.next() {
if let Some(n) = parse_rows_cols(cols) {
valid_args.push(ArgOptions::Special(SpecialSetting::Cols(n)));
} else {
return invalid_integer_arg(cols);
}
} else {
return Err(USimpleError::new(
1,
get_message_with_args(
"stty-error-invalid-integer-argument",
HashMap::from([("value".to_string(), format!("'{rows}'"))]),
),
));
return missing_arg(arg);
}
} else {
return Err(USimpleError::new(
1,
get_message_with_args(
"stty-error-missing-argument",
HashMap::from([("arg".to_string(), (*arg).to_string())]),
),
));
}
} else if arg == "columns" || arg == "cols" {
if let Some(cols) = args_iter.next() {
if let Some(n) = parse_rows_cols(cols) {
valid_args.push(ArgOptions::Special(SpecialSetting::Cols(n)));
"drain" => {
set_arg = SetArg::TCSADRAIN;
}
"-drain" => {
set_arg = SetArg::TCSANOW;
}
"size" => {
valid_args.push(ArgOptions::Print(PrintSetting::Size));
}
_ => {
// control char
if let Some(char_index) = cc_to_index(arg) {
if let Some(mapping) = args_iter.next() {
let cc_mapping = string_to_control_char(mapping).map_err(|e| {
let message = match e {
ControlCharMappingError::IntOutOfRange(val) => {
get_message_with_args(
"stty-error-invalid-integer-argument-value-too-large",
HashMap::from([(
"value".to_string(),
format!("'{val}'"),
)]),
)
}
ControlCharMappingError::MultipleChars(val) => {
get_message_with_args(
"stty-error-invalid-integer-argument",
HashMap::from([(
"value".to_string(),
format!("'{val}'"),
)]),
)
}
};
USimpleError::new(1, message)
})?;
valid_args.push(ArgOptions::Mapping((char_index, cc_mapping)));
} else {
return missing_arg(arg);
}
// baud rate
} else if let Some(baud_flag) = string_to_baud(arg) {
valid_args.push(ArgOptions::Flags(baud_flag));
// non control char flag
} else if let Some(flag) = string_to_flag(arg) {
let remove_group = match flag {
AllFlags::Baud(_) => false,
AllFlags::ControlFlags((flag, remove)) => {
check_flag_group(flag, remove)
}
AllFlags::InputFlags((flag, remove)) => check_flag_group(flag, remove),
AllFlags::LocalFlags((flag, remove)) => check_flag_group(flag, remove),
AllFlags::OutputFlags((flag, remove)) => check_flag_group(flag, remove),
};
if remove_group {
return invalid_arg(arg);
}
valid_args.push(flag.into());
// combination setting
} else if let Some(combo) = string_to_combo(arg) {
valid_args.append(&mut combo_to_flags(combo));
} else {
return Err(USimpleError::new(
1,
get_message_with_args(
"stty-error-invalid-integer-argument",
HashMap::from([("value".to_string(), format!("'{cols}'"))]),
),
));
return invalid_arg(arg);
}
} else {
return Err(USimpleError::new(
1,
get_message_with_args(
"stty-error-missing-argument",
HashMap::from([("arg".to_string(), (*arg).to_string())]),
),
));
}
} else if arg == "drain" {
set_arg = SetArg::TCSADRAIN;
} else if arg == "-drain" {
set_arg = SetArg::TCSANOW;
} else if arg == "size" {
valid_args.push(ArgOptions::Print(PrintSetting::Size));
// not a valid option
} else {
return Err(USimpleError::new(
1,
get_message_with_args(
"stty-error-invalid-argument",
HashMap::from([("arg".to_string(), (*arg).to_string())]),
),
));
}
}

Expand Down Expand Up @@ -490,6 +438,36 @@ fn stty(opts: &Options) -> UResult<()> {
Ok(())
}

fn missing_arg<T>(arg: &str) -> Result<T, Box<dyn UError>> {
Err::<T, Box<dyn UError>>(USimpleError::new(
1,
get_message_with_args(
"stty-error-missing-argument",
HashMap::from([("arg".to_string(), (*arg).to_string())]),
),
))
}

fn invalid_arg<T>(arg: &str) -> Result<T, Box<dyn UError>> {
Err::<T, Box<dyn UError>>(USimpleError::new(
1,
get_message_with_args(
"stty-error-invalid-argument",
HashMap::from([("arg".to_string(), (*arg).to_string())]),
),
))
}

fn invalid_integer_arg<T>(arg: &str) -> Result<T, Box<dyn UError>> {
Err::<T, Box<dyn UError>>(USimpleError::new(
1,
get_message_with_args(
"stty-error-invalid-integer-argument",
HashMap::from([("value".to_string(), format!("'{arg}'"))]),
),
))
}

/// GNU uses different error messages if values overflow or underflow a u8,
/// this function returns the appropriate error message in the case of overflow or underflow, or u8 on success
fn parse_u8_or_err(arg: &str) -> Result<u8, String> {
Expand Down
Loading