Skip to content

fix(printf): implement %n; report C-library conversion failures like bash - #674

Merged
brianjfox merged 1 commit into
mainfrom
fix/printf-percent-n
Aug 20, 2026
Merged

fix(printf): implement %n; report C-library conversion failures like bash#674
brianjfox merged 1 commit into
mainfrom
fix/printf-percent-n

Conversation

@brianjfox

Copy link
Copy Markdown
Owner

Summary

Fixes the two bi_printf mismatches from #665.

%n

Previously printed the literal spec and consumed no argument. Now, matching bash's printf.def case 'n':

  • binds the named variable to the byte count written so far in the current format pass — bash zeroes its tw counter on every reuse of the format string, so printf 'ab%n' u v w x sets each variable to 2
  • a missing/empty name is silently ignored (exit 0)
  • an invalid identifier (including a[0]) reports printf: `NAME': not a valid identifier and stops immediately with status 1, still writing the accumulated output (printf 'ab%ncd' 0 prints ab)
  • a failed binding (readonly variable) reports through Shell::set but leaves the exit status 0, as bash does; namerefs are followed
  • printf -v out 'ab%n' u counts bytes in the -v buffer the same way

C-library conversion failures

When snprintf refuses a conversion (field width past INT_MAX is EOVERFLOW on glibc; an unallocatable buffer is ENOMEM), gnash kept processing, printed a hardcoded macOS-flavored message at the end, and threw all output away. bash's PF macro stops immediately, reports strerror(errno), and still writes what was accumulated — gnash now does the same. (On macOS libc the huge-width case never fails — printf '%200000000000000000000s' x prints x/exit 0 in both shells — so this path mainly aligns Linux behavior.)

Verification

Byte-identical stdout/stderr/exit vs reference bash 5.3.15 on 14 %n cases (mid-format stop, format reuse, -v interplay, nameref, readonly, array-element and other invalid names, %5n) plus width/precision/%q/%5.2f/%(fmt)T regression cases. printf.tests scoreboard improves 393 → 388 diff lines (the %n mismatches are gone; remaining diffs are pre-existing option-parsing, -v validation and %.*s star-width gaps). smoke.tests passes.

Closes #665

🤖 Generated with Claude Code

…bash

Two format-string mismatches with bash (issue #665):

- %n previously printed the literal spec and consumed no argument.  It
  now binds the named variable to the byte count written so far in the
  CURRENT format pass (bash zeroes tw on every reuse of the format
  string).  A missing or empty name is ignored; an invalid identifier
  reports `NAME': not a valid identifier and stops processing with
  status 1, still writing the accumulated output; a failed binding
  (readonly) reports through Shell::set without changing the status.
  Namerefs are followed, and -v buffers count the same way.

- A conversion snprintf refuses (a field width past INT_MAX on glibc is
  EOVERFLOW; an unallocatable buffer is ENOMEM) previously kept
  processing, printed a hardcoded macOS message at the end, and threw
  ALL output away.  bash's PF macro stops immediately, reports strerror
  (errno) and still writes what was accumulated -- gnash now does the
  same.

Verified byte-identical with bash 5.3.15 on 14 %n cases (mid-format
stop, format reuse, -v interplay, namerefs, readonly, array-element and
other invalid names) plus width/precision/%q/%f/%(fmt)T regression
cases; printf.tests scoreboard improves 393 -> 388 diff lines with the
%n mismatches gone.

Closes #665
@brianjfox
brianjfox merged commit 803ea82 into main Aug 20, 2026
1 check passed
@brianjfox
brianjfox deleted the fix/printf-percent-n branch August 20, 2026 07:22
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.

Format-string mismatch in bi_printf leading to diff output vs bash

1 participant