Skip to content
Open
Show file tree
Hide file tree
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
35 changes: 22 additions & 13 deletions src/uu/unexpand/src/unexpand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -375,12 +375,19 @@ fn write_tabs(
// We never turn a single space before a non-blank into
// a tab, unless it's at the start of the line.
let ai = print_state.leading || amode;
if (ai && print_state.pctype != CharType::Tab && print_state.col > print_state.scol + 1)
if (ai

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this if is now too complex
could you please refactor it a bit ?

&& print_state.pctype != CharType::Tab
&& print_state.col > print_state.scol.saturating_add(1))
|| (print_state.col > print_state.scol
&& (print_state.leading || ai && print_state.pctype == CharType::Tab))
{
while let Some(nts) = next_tabstop(tab_config, print_state.scol) {
let target = print_state.scol + nts;
while print_state.scol < print_state.col {
let Some(nts) = next_tabstop(tab_config, print_state.scol) else {
break;
};
let Some(target) = print_state.scol.checked_add(nts) else {
break;
};
if print_state.col < target {
break;
}
Expand All @@ -389,7 +396,7 @@ fn write_tabs(
if print_state
.pending_wide
.iter()
.any(|&(start, width, _)| start < target && target < start + width)
.any(|&(start, width, _)| start < target && target < start.saturating_add(width))
{
break;
}
Expand All @@ -413,11 +420,11 @@ fn write_tabs(
{
let (_, width, bytes) = &print_state.pending_wide[wide_idx];
output.write_all(bytes)?;
print_state.scol += width;
print_state.scol = print_state.scol.saturating_add(*width);
wide_idx += 1;
} else {
output.write_all(b" ")?;
print_state.scol += 1;
print_state.scol = print_state.scol.saturating_add(1);
}
}
print_state.pending_wide.clear();
Expand Down Expand Up @@ -519,7 +526,7 @@ fn unexpand_buf(
{
write_tabs(output, tab_config, print_state, options.aflag)?;
print_state.scol = print_state.col;
print_state.col += buf.len();
print_state.col = print_state.col.saturating_add(buf.len());
output.write_all(buf)?;
return Ok(());
}
Expand All @@ -545,9 +552,9 @@ fn unexpand_buf(
let mut saw_tab = false;
while end < buf.len() {
match buf[end] {
b' ' => col += 1,
b' ' => col = col.saturating_add(1),
b'\t' => {
col += next_tabstop(tab_config, col).unwrap_or(1);
col = col.saturating_add(next_tabstop(tab_config, col).unwrap_or(1));
saw_tab = true;
}
_ => break,
Expand Down Expand Up @@ -602,10 +609,12 @@ fn unexpand_buf(
}

// compute next col, but only write space or tab chars if not buffering
print_state.col += if ctype == CharType::Space {
cwidth
print_state.col = if ctype == CharType::Space {
print_state.col.saturating_add(cwidth)
} else {
next_tabstop(tab_config, print_state.col).unwrap_or(1)
print_state
.col
.saturating_add(next_tabstop(tab_config, print_state.col).unwrap_or(1))
};

if !tabs_buffered {
Expand All @@ -619,7 +628,7 @@ fn unexpand_buf(
print_state.leading = false; // no longer at the start of a line
print_state.col = if ctype == CharType::Other {
// use computed width
print_state.col + cwidth
print_state.col.saturating_add(cwidth)
} else if print_state.col > 0 {
// Backspace case, but only if col > 0
print_state.col - 1
Expand Down
21 changes: 21 additions & 0 deletions tests/by-util/test_unexpand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,27 @@ fn test_extended_tabstop_increment_overflow() {
.stderr_contains("tab stop value is too large");
}

#[test]
fn test_tabstop_near_max_does_not_overflow() {
new_ucmd!()
.arg(format!("-t{}", usize::MAX))
.pipe_in("a\tb")
.succeeds()
.stdout_is("a\tb");

new_ucmd!()
.arg(format!("-t{}", usize::MAX - 1))
.pipe_in("a\tb")
.succeeds()
.stdout_is("a\tb");

new_ucmd!()
.arg(format!("--tabs={}", usize::MAX))
.pipe_in(" a")
.succeeds()
.stdout_is(" a");
}

#[test]
fn test_is_directory() {
let (at, mut ucmd) = at_and_ucmd!();
Expand Down
Loading