mirror of
https://https.git.savannah.gnu.org/git/findutils.git
synced 2026-01-26 07:37:52 +00:00
find: adaptive column alignment (resolves Savannah bug #45780)
* lib/listfile.c (list_file): For aligned fields, use the number of characters output to deduce whether our current idea of the maximum width of each field is too small. When this happens, increase the field width. Keep track of the field width in a static variable for each field. Do this for the inode number, number of blocks, owner, group, major and minor device numbers, and the file size. Use mbswidth in some places to count characters. * find/print.c (do_fprintf): Mention the potential portability problems in casting ino_t to uintmax_t. * bootstrap.conf (gnulib_modules): Add mbswidth. * po/Makevars (XGETTEXT_OPTIONS): updated by running bootstrap. *NEWS: Mention this bugfix.
This commit is contained in:
parent
f4dd5bdbd8
commit
731826cc8d
2
NEWS
2
NEWS
@ -3,6 +3,8 @@ GNU findutils NEWS - User visible changes. -*- outline -*- (allout)
|
||||
* Major changes in release 4.5.15-git, 2014-MM-DD
|
||||
|
||||
** Bug Fixes
|
||||
#45780: inode column is badly aligned when running 'find <dir> -ls'
|
||||
|
||||
#45585: unclear description of -newerXY in manual page.
|
||||
|
||||
#45505: give a more explicit error message when the argument to -regex
|
||||
|
||||
@ -118,6 +118,7 @@ gnulib_modules="
|
||||
math
|
||||
mbrtowc
|
||||
mbscasestr
|
||||
mbswidth
|
||||
mbsstr
|
||||
mktime
|
||||
modechange
|
||||
|
||||
@ -1001,6 +1001,11 @@ do_fprintf (struct format_val *dest,
|
||||
|
||||
case 'i': /* inode number */
|
||||
/* UNTRUSTED, but not exploitable I think */
|
||||
/* POSIX does not guarantee that ino_t is unsigned or even
|
||||
* integral (except as an XSI extension), but we'll work on
|
||||
* fixing that if we ever get a report of a system where
|
||||
* ino_t is indeed a signed integral type or a non-integral
|
||||
* arithmetic type. */
|
||||
checked_fprintf (dest, segment->text,
|
||||
human_readable ((uintmax_t) stat_buf->st_ino, hbuf,
|
||||
human_ceiling,
|
||||
|
||||
145
lib/listfile.c
145
lib/listfile.c
@ -39,6 +39,7 @@
|
||||
#include "error.h"
|
||||
#include "filemode.h"
|
||||
#include "human.h"
|
||||
#include "mbswidth.h"
|
||||
#include "idcache.h"
|
||||
#include "pathmax.h"
|
||||
#include "stat-size.h"
|
||||
@ -81,6 +82,30 @@
|
||||
|
||||
static bool print_name (register const char *p, FILE *stream, int literal_control_chars);
|
||||
|
||||
/* We have some minimum field sizes, though we try to widen these fields on systems
|
||||
* where we discover examples where the field width we started with is not enough. */
|
||||
static int inode_number_width = 9;
|
||||
static int block_size_width = 6;
|
||||
static int nlink_width = 3;
|
||||
static int owner_width = 8;
|
||||
static int group_width = 8;
|
||||
/* We don't print st_author even if the system has it. */
|
||||
static int major_device_number_width = 3;
|
||||
static int minor_device_number_width = 3;
|
||||
static int file_size_width = 8;
|
||||
|
||||
static bool print_num(FILE *stream, unsigned long num, int *width)
|
||||
{
|
||||
const int chars_out = fprintf (stream, "%*lu", *width, num);
|
||||
if (chars_out >= 0)
|
||||
{
|
||||
if (*width < chars_out)
|
||||
*width = chars_out;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/* NAME is the name to print.
|
||||
RELNAME is the path to access it from the current directory.
|
||||
@ -106,7 +131,9 @@ list_file (const char *name,
|
||||
char const *group_name;
|
||||
char hbuf[LONGEST_HUMAN_READABLE + 1];
|
||||
bool output_good = true;
|
||||
int chars_out;
|
||||
int failed_at = 000;
|
||||
int inode_field_width;
|
||||
|
||||
#if HAVE_ST_DM_MODE
|
||||
/* Cray DMF: look at the file's migrated, not real, status */
|
||||
@ -115,29 +142,50 @@ list_file (const char *name,
|
||||
strmode (statp->st_mode, modebuf);
|
||||
#endif
|
||||
|
||||
if (fprintf (stream, "%6s ",
|
||||
chars_out = fprintf (stream, "%*s", inode_number_width,
|
||||
human_readable ((uintmax_t) statp->st_ino, hbuf,
|
||||
human_ceiling,
|
||||
1u, 1u)) < 0)
|
||||
1u, 1u));
|
||||
if (chars_out < 0)
|
||||
{
|
||||
output_good = false;
|
||||
failed_at = 100;
|
||||
}
|
||||
|
||||
else if (chars_out > inode_number_width)
|
||||
{
|
||||
inode_number_width = chars_out;
|
||||
}
|
||||
if (output_good)
|
||||
{
|
||||
if (fprintf (stream, "%4s ",
|
||||
if (EOF == putc(' ', stream))
|
||||
{
|
||||
output_good = false;
|
||||
failed_at = 150;
|
||||
}
|
||||
chars_out = fprintf (stream, "%*s",
|
||||
block_size_width,
|
||||
human_readable ((uintmax_t) ST_NBLOCKS (*statp), hbuf,
|
||||
human_ceiling,
|
||||
ST_NBLOCKSIZE, output_block_size)) < 0)
|
||||
ST_NBLOCKSIZE, output_block_size));
|
||||
if (chars_out < 0)
|
||||
{
|
||||
output_good = false;
|
||||
failed_at = 200;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (chars_out > block_size_width)
|
||||
block_size_width = chars_out;
|
||||
}
|
||||
}
|
||||
|
||||
if (output_good)
|
||||
{
|
||||
if (EOF == putc(' ', stream))
|
||||
{
|
||||
output_good = false;
|
||||
failed_at = 250;
|
||||
}
|
||||
/* modebuf includes the space between the mode and the number of links,
|
||||
as the POSIX "optional alternate access method flag". */
|
||||
if (fprintf (stream, "%s%3lu ", modebuf, (unsigned long) statp->st_nlink) < 0)
|
||||
@ -149,16 +197,27 @@ list_file (const char *name,
|
||||
|
||||
if (output_good)
|
||||
{
|
||||
if (EOF == putc(' ', stream))
|
||||
{
|
||||
output_good = false;
|
||||
failed_at = 250;
|
||||
}
|
||||
user_name = getuser (statp->st_uid);
|
||||
if (user_name)
|
||||
{
|
||||
output_good = (fprintf (stream, "%-8s ", user_name) >= 0);
|
||||
int len = mbswidth (user_name, 0);
|
||||
if (len > owner_width)
|
||||
owner_width = len;
|
||||
output_good = (fprintf (stream, "%-*s ", owner_width, user_name) >= 0);
|
||||
if (!output_good)
|
||||
failed_at = 400;
|
||||
}
|
||||
else
|
||||
{
|
||||
output_good = (fprintf (stream, "%-8lu ", (unsigned long) statp->st_uid) >= 0);
|
||||
chars_out = fprintf (stream, "%-8lu ", (unsigned long) statp->st_uid);
|
||||
if (chars_out > owner_width)
|
||||
owner_width = chars_out;
|
||||
output_good = (chars_out > 0);
|
||||
if (!output_good)
|
||||
failed_at = 450;
|
||||
}
|
||||
@ -169,32 +228,70 @@ list_file (const char *name,
|
||||
group_name = getgroup (statp->st_gid);
|
||||
if (group_name)
|
||||
{
|
||||
output_good = (fprintf (stream, "%-8s ", group_name) >= 0);
|
||||
int len = mbswidth (group_name, 0);
|
||||
if (len > group_width)
|
||||
group_width = len;
|
||||
output_good = (fprintf (stream, "%-*s ", group_width, group_name) >= 0);
|
||||
if (!output_good)
|
||||
failed_at = 500;
|
||||
}
|
||||
else
|
||||
{
|
||||
output_good = (fprintf (stream, "%-8lu ", (unsigned long) statp->st_gid) >= 0);
|
||||
chars_out = fprintf (stream, "%-*lu",
|
||||
group_width, (unsigned long) statp->st_gid);
|
||||
if (chars_out > group_width)
|
||||
group_width = chars_out;
|
||||
output_good = (chars_out >= 0);
|
||||
if (output_good)
|
||||
{
|
||||
if (EOF == putc(' ', stream))
|
||||
{
|
||||
output_good = false;
|
||||
failed_at = 525;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!output_good)
|
||||
failed_at = 550;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (output_good)
|
||||
{
|
||||
if (S_ISCHR (statp->st_mode) || S_ISBLK (statp->st_mode))
|
||||
{
|
||||
#ifdef HAVE_STRUCT_STAT_ST_RDEV
|
||||
if (fprintf (stream, "%3lu, %3lu ",
|
||||
if (!print_num (stream,
|
||||
(unsigned long) major (statp->st_rdev),
|
||||
(unsigned long) minor (statp->st_rdev)) < 0)
|
||||
&major_device_number_width))
|
||||
{
|
||||
output_good = false;
|
||||
failed_at = 600;
|
||||
}
|
||||
if (output_good)
|
||||
{
|
||||
if (fprintf (stream, ", ") < 0)
|
||||
{
|
||||
output_good = false;
|
||||
failed_at = 625;
|
||||
}
|
||||
}
|
||||
if (output_good)
|
||||
{
|
||||
if (!print_num (stream,
|
||||
(unsigned long) minor (statp->st_rdev),
|
||||
&minor_device_number_width))
|
||||
{
|
||||
output_good = false;
|
||||
failed_at = 650;
|
||||
}
|
||||
}
|
||||
#else
|
||||
if (fprintf (stream, " ") < 0)
|
||||
if (fprintf (stream, "%*s %*s",
|
||||
major_device_number_width,
|
||||
minor_device_number_width) < 0)
|
||||
{
|
||||
output_good = false;
|
||||
failed_at = 700;
|
||||
@ -203,15 +300,33 @@ list_file (const char *name,
|
||||
}
|
||||
else
|
||||
{
|
||||
if (fprintf (stream, "%8s ",
|
||||
const int blocksize = output_block_size < 0 ? output_block_size : 1;
|
||||
chars_out = fprintf (stream, "%*s",
|
||||
file_size_width,
|
||||
human_readable ((uintmax_t) statp->st_size, hbuf,
|
||||
human_ceiling,
|
||||
1,
|
||||
output_block_size < 0 ? output_block_size : 1)) < 0)
|
||||
1, blocksize));
|
||||
if (chars_out < 0)
|
||||
{
|
||||
output_good = false;
|
||||
failed_at = 800;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (chars_out > file_size_width)
|
||||
{
|
||||
file_size_width = chars_out;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (output_good)
|
||||
{
|
||||
if (EOF == putc(' ', stream))
|
||||
{
|
||||
output_good = false;
|
||||
failed_at = 850;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
12
po/Makevars
12
po/Makevars
@ -8,7 +8,17 @@ subdir = po
|
||||
top_builddir = ..
|
||||
|
||||
# These options get passed to xgettext.
|
||||
XGETTEXT_OPTIONS = --keyword=_ --keyword=N_ --from-code=UTF-8
|
||||
XGETTEXT_OPTIONS = --keyword=_ --keyword=N_ \
|
||||
\
|
||||
--flag=_:1:pass-c-format\
|
||||
--flag=N_:1:pass-c-format\
|
||||
--flag=error:3:c-format --flag=error_at_line:5:c-format\
|
||||
\
|
||||
--from-code=UTF-8\
|
||||
--flag=asprintf:2:c-format --flag=vasprintf:2:c-format\
|
||||
--flag=asnprintf:3:c-format --flag=vasnprintf:3:c-format\
|
||||
--flag=wrapf:1:c-format\
|
||||
$${end_of_xgettext_options+}
|
||||
|
||||
# This is the copyright holder that gets inserted into the header of the
|
||||
# $(DOMAIN).pot file. Set this to the copyright holder of the surrounding
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user