bugfindutils - Bugs: bug #10609, Inconsistent behaviour of...


bug #10609: Inconsistent behaviour of printf-style format specifiers

Submitted by:  James Youngman <jay>
Submitted on:  Thu 07 Oct 2004 10:21:52 PM UTC  
Category:  find Severity:  1 - Wish
Item Group:  None Status:  Wont Fix
Privacy:  Public Assigned to:  James Youngman <jay>
Originator Name:  Chris Chittleborough Open/Closed:  Closed
Release:  None Fixed Release:  4.2.5

Add a New Comment (Rich Markup)

You are not logged in

Please log in, so followups can be emailed to you.


Fri 19 Nov 2004 11:25:24 PM UTC, comment #5: 

Going ahead with the plan to close the bug report as described in my earlier update.  Please open a new bug report specifically on the printf format specifier flags if you feel that the documentation change is not sufficient, and the actual functionality should in fact change, or (especially) if you can think of a good fix for the problem.   Thanks.

James Youngman <jay>
Project AdministratorIn charge of this item.
Wed 10 Nov 2004 11:15:39 PM UTC, comment #4: 

Postpone further action until I hear from Chris.

James Youngman <jay>
Project AdministratorIn charge of this item.
Wed 10 Nov 2004 11:15:09 PM UTC, comment #3: 

I have applied something very similar to your patch.  I have also documented it. 

As indicated in my earlier comment, I propose not to change the code now that the behaviour is documented for the %d and %m specifiers (versus everything else).  The rationale behind this is that it's very difficult to portably print uintmax_t values on systems that don't have support for that in their fprintf library function.

Hence I plan to close the bug report as resolved.  Do you have any objections or other comments?

James Youngman <jay>
Project AdministratorIn charge of this item.
Wed 10 Nov 2004 10:42:20 PM UTC, comment #2: 

Thanks for the detailed bug report.  I've examined the code and now understand why it does what it does.   In short, most of the numeric fileds from struct stat are not defined by POSIX to fit into a "long".   That means that we can't rely on being able to print them with %ld.  POSIX requires that implementations provide an environment in which a subset fit into a long but there is no guarantee that we're running in it, and in any case some of the fields we are interested in are not among the fields POSIX requires to fit into a long. 

The findutils code uses human_readable() to print these values.  That uses a uintmax_t type, which might have been defined by config.h as "unsigned long long" on systems that have no native uintmax_t.  Hence once human_readable() has done its work, the resulting field is printed with %s.    Therefore the flags are passed to printf(), but of course printf() ignores them.

To honour the flag characters we would either need to post-process the result of human-readable or figure out a way of getting printf() to print a value of type uintmax_t even on a system which doesn't natively support such a type (for example because it is a GCC extension and we are using the system's C library).

For now, I have opted to document the current behaviour rather than change the code (though I have put comments in the code explaining what is happening).

James Youngman <jay>
Project AdministratorIn charge of this item.
Sun 10 Oct 2004 10:55:32 AM UTC, comment #1: 

FURTHER THOUGHTS: I've been thinking about how find's format codes should work in an ideal world, and came up with the following proposal.  The lines beginning with two plus signs describe changes to find's current behaviour.

   a string last access time in ctime() format
   A<K> string last access time using strftime() code <K>
   b integer size in 512-byte blocks, rounded up
   c string status change time in ctime() format
   C<K> string status change time using strftime() code <K>
   d integer depth
   f string file name (= basename(%p))
   F string filesystem type (a string)
   g string group name (or number)
   G integer group number
   h string directory (= dirname(%p))
   H string command-line arg under which file was found
   i integer inode number in decimal
   k integer size in 1K blocks, rounded up
   l string target of symlink; "" for non-symlinks
   m special modes (really permissions) in octal
++ M string mode in string format (eg., "drwxr-xr-x")
   n integer number of hard links
   p string file's path
   P string file's path with command-line arg (=%H) removed
   s integer size in bytes
++ S string size in human-friendly notation (like df -h)
   t string last modification time in ctime() format
   T<K> string last modification using strftime() code <K>
   u string user name (or number)
   U integer user number

 String-style conversions are of the form
   "%" {<str-flag>} [<min-width>] ["."<max-length>] <code>
 where <str-flag> can be
"-" for left-justification (iff <width> specified),
++   or "#" for Unix-style (backslashed) quoting.
 This could be implemented by using a "%[-][<width>][.<max-length>]s" format
 with fprintf().  (If "#" is specified, a backslash-escaped string is used
 instead of the original string.  Note that the -ls predicate performs
 backslash-escaping of pathnames.)

 Number-style conversions are of the form
   "%" {<num-flag>} [<min-width>] ["."<min-digits>] <code>
 where <num-flag> can be
"-" for left-justification (iff <width> specified),
++ "0" to pad with leading zeros instead of spaces (ignored if "-" used),
++ "+" to output a plus sign before the digits,
++ " " to output a space before the digits (ignored if "+" used),
++   or "'" to group digits in a locale-specific way.
 This could be implemented by using a "%{<num-flag>}[<width>][.<min-digits>]u"
 format with fprintf(), modulo type modifiers.
++ * I suspect that most find users would expect the "0", "+" and " " flags
++   and the ".<min-digits>" specifier to be supported for numeric
++   conversions; certainly I was suprised to find they weren't.
++ * I think the "'" flag would be a useful addition to find.
++ * if "'" is used and the local fprintf() does not support "'" itself, we
++   have to insert the grouping separators (and pad the result) ourselves.
  (Version 2 of the Single UNIX Specification, which dates back to 1997,
  requires support for the "'" flag.)

 The %m format is of the form
   "%" {<m-flag>} [<min-width>] ["."<min-digits>] "m"
 where <m-flag> can be
"-" for left-justification (iff <width> specified),
++   or "#" to force a leading zero.
 This can be implemented using a "%{<m-flag>}<min-width>.<min-digits>o" format
 with fprintf().
++ * We always specify both <min-width> and <min-digits>.
++ * <min-digits> defaults to 3, to match most people's expectations.
++ * <min-width> probably should default to 5.

Even with the above changes, it is not possible to write a printf format which
is equivalent to -ls. With three more changes, it would be possible:
  * Let %s with a "#" flag behave differently with block and character
    devices: instead of printing a meaningless number, print the major and
    minor device numbers in "%3u, %3u" format.
  * Add a %L code, which generates "-> %l" for symbolic links and zero
    characters for everything else.
  * Add a time format code, possibly "-", which uses the strftime() formats
    "%a %b %d %H:%M" (for timestamps in the previous six months) or
    "%a %b %d  %y" (for all other timestamps).
Then -ls would be identical to
-printf '%6i %4k %M %3n %0-8.8u %-8.8g %#8s %T- %p%L\n'
except that -ls uses %4b instead of %4k in POSIXLY_CORRECT mode.

Chris(topher) Chittleborough <cchittleborough>
Thu 07 Oct 2004 10:21:52 PM UTC, original submission:  

Dan Jacobson recently pointed out a documentation problem regarding
find's format strings.  Here is a fuller explanation of the situation as
of find 4.1.20.  (I sent this to bug-findutils back in August but got no
response; maybe sending it during the summer vacation period for you
Northern Hemisphere dwellers wasn't such a great move ...)

I have written a patch which adds a new format code (%M -> ls-style
10-character mode string) and a new time format (%T+ ->
yyyy-mm-dd+HH:MM:SS) to find.  Thanks to the really clean internal
structure of the source, coding this enhancement was quite easy.  But I
have run into some problems while documenting the new format features.

In find.texi, the "Print File Information" node says about "-printf" that
   Field widths and precisions can be specified as with the
   `printf' C function
which is true but quite incomplete.  On the other hand, the "Format
Directives" node says that
   [u]nlike the C `printf' function, ["-printf" and
   "-fprintf"] do not support field width specifiers
which is quite untrue.

Here's the full truth as of version 4.1.20. Find accepts the syntax
   '%' {'-' | '0' | '#' | '+' | ' ' } Number [ '.' Number ] Directive
for format conversions, but only honors the '0', '#', '+' and ' ' flags
with two directives, %d (depth) and %m (mode).  You might expect numeric
directives like %s, %n and %i to behave like %d, but they don't.  In a
closely-related development, with %d and %m a precision specification
(eg., the ".4" in "%.4m") specifies the minimum number of digits to be
output, but with all other directives (even %s!) it specifies the
maximum output length.  (The reason for this is that %d and %m are
implemented using fprintf's numeric conversions -- %d (decimal) and %o
(octal) respectively -- while all the other directives use fprintf's %s
(string) conversion.)
There is another complication with %m.  You might expect that it would
always output 3 octal digits or 4 iff the setuid, setgid or sticky bits
are set.  However, a file with mode 044 (unlikely, but I've done ... er,
that is, seen ... stranger things), causes "%m" to output "44", not

All this is confusing and hard to document.  Perhaps %d and %o should be
brought into line with the other directives?  But this might break
existing scripts.  Does the fact that these details were not documented
make it acceptable to change them?  Perhaps more importantly, what does
POSIX say about this stuff?  (Having never even seen any POSIX
specification, I have no idea.)

If the people on this list can reach some sort of consensus, I'm willing
to try to produce a patch.

James Youngman <jay>
Project AdministratorIn charge of this item.


(Note: upload size limit is set to 16384 kB, after insertion of the required escape characters.)

Attach Files:

Attached Files
file #1975:  format-documentation.diff added by jay (7KiB - text/x-patch)
file #1847:  CodeOnly.patch added by cchittleborough (2KiB - application/octet-stream - FYI, here's a code-only patch to add %M and the "+" timestamp option.)


Depends on the following items: None found

Items that depend on this one: None found


CC list is empty


Do you think this task is very important?
If so, you can add your encouragement to it.
This task has 0 encouragements so far.

Only logged-in users can vote.




Follow 6 latest changes.

Date Changed by Updated Field Previous Value => Replaced by
2004-11-19 jay StatusPostponed => Wont Fix
    Open/ClosedOpen => Closed
    Fixed ReleaseNone => 4.2.5
2004-11-10 jay StatusNone => Postponed
2004-11-10 jay Attached File- => Added format-documentation.diff, #1859
2004-10-10 cchittleborough Attached File- => Added CodeOnly.patch, #1748

Back to the top

Powered by Savane 3.5