Skip to content

Commit 76194d6

Browse files
committed
fix(quoting): prevent control chars from triggering quotes in NonEscapedShellQuoter
The initial_quoting_with_show_control function was incorrectly treating control characters as requiring quoting when show_control=true. This caused test_control_chars to fail in the MinRustV CI check. For NonEscapedShellQuoter (used in ls --quoting-style=shell): - Control chars should NOT trigger quoting - When show_control=false: they become '?' (not special) - When show_control=true: shown as-is but still don't need quotes - Only characters in shell_escaped_char_set trigger quoting This differs from EscapedShellQuoter which uses dollar-quoting for control characters. Fixes the test expectation where shell-show mode should NOT wrap control characters in quotes unless always_quote is set.
1 parent 1344135 commit 76194d6

File tree

2 files changed

+18
-17
lines changed

2 files changed

+18
-17
lines changed

src/uucore/src/lib/features/format/spec.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -358,7 +358,7 @@ impl Spec {
358358
let (width, neg_width) = resolve_asterisk_width(*width, args).unwrap_or_default();
359359
write_padded(
360360
writer,
361-
&[args.next_char(position)],
361+
&[args.next_char(*position)],
362362
width,
363363
*align_left || neg_width,
364364
)
@@ -378,7 +378,7 @@ impl Spec {
378378
// TODO: We need to not use Rust's formatting for aligning the output,
379379
// so that we can just write bytes to stdout without panicking.
380380
let precision = resolve_asterisk_precision(*precision, args);
381-
let os_str = args.next_string(position);
381+
let os_str = args.next_string(*position);
382382
let bytes = os_str_as_bytes(os_str)?;
383383

384384
let truncated = match precision {
@@ -388,7 +388,7 @@ impl Spec {
388388
write_padded(writer, truncated, width, *align_left || neg_width)
389389
}
390390
Self::EscapedString { position } => {
391-
let os_str = args.next_string(position);
391+
let os_str = args.next_string(*position);
392392
let bytes = os_str_as_bytes(os_str)?;
393393
let mut parsed = Vec::<u8>::new();
394394

@@ -424,7 +424,7 @@ impl Spec {
424424
} => {
425425
let (width, neg_width) = resolve_asterisk_width(*width, args).unwrap_or((0, false));
426426
let precision = resolve_asterisk_precision(*precision, args).unwrap_or_default();
427-
let i = args.next_i64(position);
427+
let i = args.next_i64(*position);
428428

429429
if precision as u64 > i32::MAX as u64 {
430430
return Err(FormatError::InvalidPrecision(precision.to_string()));
@@ -452,7 +452,7 @@ impl Spec {
452452
} => {
453453
let (width, neg_width) = resolve_asterisk_width(*width, args).unwrap_or((0, false));
454454
let precision = resolve_asterisk_precision(*precision, args).unwrap_or_default();
455-
let i = args.next_u64(position);
455+
let i = args.next_u64(*position);
456456

457457
if precision as u64 > i32::MAX as u64 {
458458
return Err(FormatError::InvalidPrecision(precision.to_string()));
@@ -483,7 +483,7 @@ impl Spec {
483483
} => {
484484
let (width, neg_width) = resolve_asterisk_width(*width, args).unwrap_or((0, false));
485485
let precision = resolve_asterisk_precision(*precision, args);
486-
let f: ExtendedBigDecimal = args.next_extended_big_decimal(position);
486+
let f: ExtendedBigDecimal = args.next_extended_big_decimal(*position);
487487

488488
if precision.is_some_and(|p| p as u64 > i32::MAX as u64) {
489489
return Err(FormatError::InvalidPrecision(
@@ -520,7 +520,7 @@ fn resolve_asterisk_width(
520520
match option {
521521
None => None,
522522
Some(CanAsterisk::Asterisk(loc)) => {
523-
let nb = args.next_i64(&loc);
523+
let nb = args.next_i64(loc);
524524
if nb < 0 {
525525
Some((usize::try_from(-(nb as isize)).ok().unwrap_or(0), true))
526526
} else {
@@ -539,7 +539,7 @@ fn resolve_asterisk_precision(
539539
) -> Option<usize> {
540540
match option {
541541
None => None,
542-
Some(CanAsterisk::Asterisk(loc)) => match args.next_i64(&loc) {
542+
Some(CanAsterisk::Asterisk(loc)) => match args.next_i64(loc) {
543543
v if v >= 0 => usize::try_from(v).ok(),
544544
v if v < 0 => Some(0usize),
545545
_ => None,

src/uucore/src/lib/features/quoting_style/shell_quoter.rs

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -398,16 +398,17 @@ fn initial_quoting_with_show_control(
398398
input: &[u8],
399399
dirname: bool,
400400
always_quote: bool,
401-
show_control: bool,
401+
_show_control: bool,
402402
) -> (Quotes, bool) {
403-
// Check for control characters FIRST - they require $'...' which only works with single quotes
404-
// But only consider them if we're showing them; if hiding, they become '?' which isn't special
405-
let has_control_chars = show_control && input.iter().any(|&c| c < 32 || c == 127);
406-
407-
if has_control_chars
408-
|| input
409-
.iter()
410-
.any(|c| shell_escaped_char_set(dirname).contains(c))
403+
// For NonEscapedShellQuoter, control chars don't trigger quoting.
404+
// When show_control=false, they become '?' which isn't special.
405+
// When show_control=true, they're shown as-is but still don't trigger quoting
406+
// (unlike EscapedShellQuoter which uses dollar-quoting for them).
407+
// Only characters in shell_escaped_char_set trigger quoting.
408+
409+
if input
410+
.iter()
411+
.any(|c| shell_escaped_char_set(dirname).contains(c))
411412
{
412413
(Quotes::Single, true)
413414
} else if input.contains(&b'\'') {

0 commit comments

Comments
 (0)