Skip to content

find: support precision and the + space # 0 flags in -printf - #918

Open
jayhemnani9910 wants to merge 3 commits into
uutils:mainfrom
jayhemnani9910:printf-precision-and-flags
Open

jayhemnani9910 wants to merge 3 commits into
uutils:mainfrom
jayhemnani9910:printf-precision-and-flags

Conversation

@jayhemnani9910

@jayhemnani9910 jayhemnani9910 commented Oct 24, 2026 •

Copy link
Copy Markdown
Contributor

-printf only understands - and a width. A precision or any other flag makes the whole directive print literally with a warning:

$ find d/f1 -printf '%.3p|%05m|%+d|%#m\n'
GNU 4.10: d/f|00664|+0|0664
main:     find: warning: unrecognized format directive '%.'
          %.3p|  664|%+d|%#m      (plus warnings for %+ and %#)

GNU treats %d and %m as integers (C %d and %o): precision is the minimum number of digits, + and space add a sign to %d, # gives %m a leading 0, and 0 pads with zeros when there is no precision and no -. Every other directive is a string: precision cuts it, in bytes (%.3p, %.3Tc, %.1i), and +, space, # and 0 change nothing. As in GNU, 0 is only taken after the other flags (%0-5d stays an unrecognized directive, printed as written). The width is counted in bytes too, as in GNU. %S is left as it is (#842 changes its format).

The parser now records the flags and a precision on each directive, and apply_precision_and_flags applies them to the formatted value before the width.

New tests test_parse_precision_and_flags, test_printf_precision_and_flags, and four more for a big precision and depth 0, unrecognized directives, a non-ASCII name, and %m on modes 644, 000 and 4755. cargo test passes, clippy and fmt clean. Every directive with eight flag and precision mixes (200 formats, %S left out) prints the same as GNU find 4.10.0 over a directory, files, a symlink and a name with a space.

Copilot AI balanced review requested due to automatic review settings October 24, 2026 07:21

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota.

An organization owner can choose the repository organization as the billing source for reviews requested by members with a paid Copilot license. Learn about Copilot code review billing. Review the Copilot code review billing settings.

@github-actions

Copy link
Copy Markdown

Commit 3a17aed has test result changes:

bfs testsuite:

Test results comparison:
  Current:   TOTAL: 317 / PASSED: 277 / FAILED: 34 / SKIPPED: 6
  Reference: TOTAL: 317 / PASSED: 276 / FAILED: 35 / SKIPPED: 6

Changes from main branch:
  TOTAL: +0
  PASSED: +1
  FAILED: -1

Test improvements (1):
  + gnu/printf_flags

@codspeed

codspeed Bot commented Oct 24, 2026 •

Copy link
Copy Markdown

Merging this PR will not alter performance

1 warning

⚠️ 15 benchmarks are dominated by system calls

System calls cannot be simulated consistently and are left out of the measure. The reported value understates the real cost. Switch to the Walltime instrument to measure them.

Learn more about system calls

See affected benchmarks

✅ 20 untouched benchmarks


Comparing jayhemnani9910:printf-precision-and-flags (97e39e5) with main (51f3499)

Open in CodSpeed

@codecov

codecov Bot commented Oct 24, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 98.52217% with 3 lines in your changes missing coverage. Please review.
✅ Project coverage is 92.76%. Comparing base (148f36f) to head (97e39e5).
⚠️ Report is 2 commits behind head on main.

Files with missing lines Patch % Lines
src/find/matchers/printf.rs 98.52% 2 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #918      +/-   ##
==========================================
+ Coverage   92.62%   92.76%   +0.14%     
==========================================
  Files          37       37              
  Lines        7808     8005     +197     
  Branches      392      402      +10     
==========================================
+ Hits         7232     7426     +194     
- Misses        435      437       +2     
- Partials      141      142       +1     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

// safe to unwrap: .front() already succeeded above.
self.advance_one().unwrap();
}
// GNU find only takes `0` after the other flags.

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.

could you please add a test for %0-5d staying unrecognized?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Added in 95392e5. It also showed that we printed %-5d there: the literal kept only the directive letter. An unrecognized directive now prints its whole text, as GNU find does (%0-5d, %5z and %+.2z stay as written).

Comment thread src/find/matchers/printf.rs Outdated
let width = self.parse_format_width()?;
let precision = if self.front()? == '.' {
self.advance_one()?;
Some(self.parse_format_width()?.unwrap_or(0))

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.

a big precision will fail with "Format width too large", ok with that?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Not ok, GNU takes it: %.70000f prints the name. The precision no longer has the u16 limit (95392e5). For names it only cuts, and for numbers the zeros are added with repeat instead of a format width. The width keeps its limit.

Comment thread src/find/matchers/printf.rs Outdated
FormatDirective::Sparseness => return content,
_ => {
return match precision {
Some(precision) => content.chars().take(precision).collect::<String>().into(),

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.

GNU cuts bytes here, not chars, no?
does %.2f on a non-ascii name match?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Right, it did not match: GNU cuts bytes, even inside a character, and pads the width in bytes too. On é_ab, %.3f|%5.2f|%-5.1f| gives é_| é|\xc3 |. Both are byte-based now (95392e5), and the output is written as bytes. A test checks those three.

}

#[test]
fn test_printf_precision_and_flags() {

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.

please add the %m cases too (%#m, %05m, %#.0m), and %.0d on depth 0
the octal branch isn't tested at all

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Added in 95392e5: %#m|%05m|%#.0m|%#5m|%#05m|%.0m| on modes 644, 000 and 4755, and %.0d|%.1d|%#d| at depth 0 (|0|0|). All the expected outputs come from GNU find 4.10.0. The branch is also rebased on main, which now prints %m with the special bits and no zero padding.

@jayhemnani9910
jayhemnani9910 force-pushed the printf-precision-and-flags branch from 3a17aed to 95392e5 Compare October 24, 2026 18:51
Copilot AI balanced review requested due to automatic review settings October 24, 2026 18:51

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota.

An organization owner can choose the repository organization as the billing source for reviews requested by members with a paid Copilot license. Learn about Copilot code review billing. Review the Copilot code review billing settings.

@github-actions

Copy link
Copy Markdown

Commit 95392e5 has test result changes:

bfs testsuite:

Test results comparison:
  Current:   TOTAL: 317 / PASSED: 278 / FAILED: 33 / SKIPPED: 6
  Reference: TOTAL: 316 / PASSED: 276 / FAILED: 34 / SKIPPED: 6

Changes from main branch:
  TOTAL: +1
  PASSED: +2
  FAILED: -1

Test improvements (1):
  + gnu/printf_flags

digits.clear();
}
if let Some(precision) = precision {
let zeros = precision.saturating_sub(digits.len());

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.

with the u16 limit gone, %.9999999999d will try to allocate ~10GB here, no?
maybe cap the precision for %d/%m (GNU fails above INT_MAX)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yes, it would. Fixed in 97e39e5: a precision above INT_MAX now prints nothing for that directive, the rest of the format still prints, and find exits 1 with 'standard output': Value too large for defined data type, as GNU find 4.10 does. This applies to every directive, as in GNU, and a precision too large for usize is treated the same way instead of failing to parse. One difference: we report it once, like other stdout errors, where GNU repeats it for each file. New test find_printf_precision_too_large.

Copilot AI balanced review requested due to automatic review settings October 25, 2026 14:48

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota.

An organization owner can choose the repository organization as the billing source for reviews requested by members with a paid Copilot license. Learn about Copilot code review billing. Review the Copilot code review billing settings.

@github-actions

Copy link
Copy Markdown

Commit 97e39e5 has test result changes:

bfs testsuite:

Test results comparison:
  Current:   TOTAL: 317 / PASSED: 278 / FAILED: 33 / SKIPPED: 6
  Reference: TOTAL: 317 / PASSED: 277 / FAILED: 34 / SKIPPED: 6

Changes from main branch:
  TOTAL: +0
  PASSED: +1
  FAILED: -1

Test improvements (1):
  + gnu/printf_flags

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants