Skip to content

Commit 6df507e

Browse files
committed
Implemented hex and octal parsing for row columns for stty
1 parent b2d1117 commit 6df507e

File tree

2 files changed

+41
-4
lines changed

2 files changed

+41
-4
lines changed

src/uu/stty/src/stty.rs

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -471,11 +471,20 @@ fn parse_u8_or_err(arg: &str) -> Result<u8, String> {
471471

472472
/// GNU uses an unsigned 32-bit integer for row/col sizes, but then wraps around 16 bits
473473
/// this function returns Some(n), where n is a u16 row/col size, or None if the string arg cannot be parsed as a u32
474+
/// Supports decimal, hexadecimal (0x prefix), and octal (0 prefix) formats
474475
fn parse_rows_cols(arg: &str) -> Option<u16> {
475-
if let Ok(n) = arg.parse::<u32>() {
476-
return Some((n % (u16::MAX as u32 + 1)) as u16);
477-
}
478-
None
476+
let n = if let Some(hex) = arg.strip_prefix("0x").or_else(|| arg.strip_prefix("0X")) {
477+
u32::from_str_radix(hex, 16).ok()?
478+
} else if let Some(octal) = arg.strip_prefix('0') {
479+
if octal.is_empty() {
480+
0
481+
} else {
482+
u32::from_str_radix(octal, 8).ok()?
483+
}
484+
} else {
485+
arg.parse::<u32>().ok()?
486+
};
487+
Some((n % (u16::MAX as u32 + 1)) as u16)
479488
}
480489

481490
fn check_flag_group<T>(flag: &Flag<T>, remove: bool) -> bool {

tests/by-util/test_stty.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,34 @@ fn row_column_sizes() {
282282
.stderr_contains("missing argument to 'rows'");
283283
}
284284

285+
#[test]
286+
#[cfg(unix)]
287+
fn test_row_column_hex_octal() {
288+
let (path, _controller, _replica) = pty_path();
289+
let (_at, ts) = at_and_ts!();
290+
291+
// Test various numeric formats: hex (0x1E), octal (036), uppercase hex (0X1E), decimal (30), and zero
292+
let test_cases = [
293+
("rows", "0x1E"), // hexadecimal = 30
294+
("rows", "036"), // octal = 30
295+
("cols", "0X1E"), // uppercase hex = 30
296+
("columns", "30"), // decimal = 30
297+
("rows", "0"), // zero (not octal prefix)
298+
];
299+
300+
for (setting, value) in test_cases {
301+
let result = ts.ucmd().args(&["--file", &path, setting, value]).run();
302+
let exp_result =
303+
unwrap_or_return!(expected_result(&ts, &["--file", &path, setting, value]));
304+
let normalized_stderr = normalize_stderr(result.stderr_str());
305+
306+
result
307+
.stdout_is(exp_result.stdout_str())
308+
.code_is(exp_result.code());
309+
assert_eq!(normalized_stderr, exp_result.stderr_str());
310+
}
311+
}
312+
285313
#[test]
286314
#[cfg(any(target_os = "linux", target_os = "android"))]
287315
fn line() {

0 commit comments

Comments
 (0)