bug-coreutils
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Badly formatted 'ls -l'


From: Paul Eggert
Subject: Re: Badly formatted 'ls -l'
Date: 03 Dec 2003 02:12:52 -0800
User-agent: Gnus/5.09 (Gnus v5.9.0) Emacs/21.3

Leah <address@hidden> writes:

> `ls -l` sometimes incorrectly formats output due to naively assuming
> file sizes cannot be larger than 8 digits.  The following patch corrects
> this.

Thanks for your bug report.  That patch uncovers a few more problems
in 'ls' with column widths (including some potential buffer overruns,
sigh).  Rather than fix the problems piecemeal, how about if we adjust
'ls' so that it adjusts all the column widths to fit the data, not
just the file sizes?  Here's a proposed patch, relative to CVS
coreutils.

2003-12-03  Paul Eggert  <address@hidden>

        * NEWS: ls -l (and similar options) now adjust all columns to
        fit the data.  Generalized from a suggestion by Leah Q for file sizes.
        * doc/coreutils.texi (What information is listed, chroot
        invocation): Adjust example 'ls' output to match new behavior
        with narrower output columns.
        (The cut command): Remove example that cut the output of
        'ls -l'.  The output was incorrect even with the old 'ls',
        and the whole idea of using 'cut' on 'ls -l' output is bogus
        anyway.
        * src/ls.c (INODE_DIGITS, LOGIN_NAME_MAX, ID_LENGTH_MAX): Remove.
        (format_user_width, format_group_width, unsigned_file_size,
        format_group): New functions.
        (block_size_width): Renamed from block_size_size.
        (inode_number_width, nlink_width, owner_width, group_width,
        author_width, major_device_number_width, minor_device_number_width,
        file_size_width): New vars.
        (clear_files): Initialize them.
        (gobble_file): Set them.  Don't ceiling block_size_width to 7.
        (print_long_file): Use them.
        (gobble_file): Use a new local variable 'f' to make the code
        smaller and more consistent with other functions.
        (format_user): Output to stdout, not to a buffer, so that we
        don't have to worry about buffer overrun.  Update dired_pos.
        (print_long_file): Don't put owner, group, author into buffer;
        just print them directly.  Don't assume link counts and
        major and minor numbers fit into unsigned long int.
        * tests/cp/same-file, tests/mv/part-symlink: Don't assume that
        'ls' output is fixed-width.

Index: NEWS
===================================================================
RCS file: /cvsroot/coreutils/coreutils/NEWS,v
retrieving revision 1.149
diff -p -u -r1.149 NEWS
--- NEWS        27 Nov 2003 08:18:45 -0000      1.149
+++ NEWS        3 Dec 2003 09:28:23 -0000
@@ -29,6 +29,13 @@ GNU coreutils NEWS                      
   (--dereference-args, aka -D) rather then the current meaning of --si.
   Now, using -H elicits a warning to that effect.
 
+  When given -l and similar options, ls now adjusts the output column
+  widths to fit the data, so that output lines are shorter and have
+  columns that line up better.  This may adversely affect shell
+  scripts that expect fixed-width columns, but such shell scripts were
+  not portable anyway, even with old GNU ls where the columns became
+  ragged when a datum was too wide.
+
 ** Bug fixes
 
   printf, seq, tail, and sleep now parse floating-point operands
Index: doc/coreutils.texi
===================================================================
RCS file: /cvsroot/coreutils/coreutils/doc/coreutils.texi,v
retrieving revision 1.142
diff -p -u -r1.142 coreutils.texi
--- doc/coreutils.texi  27 Nov 2003 07:58:32 -0000      1.142
+++ doc/coreutils.texi  3 Dec 2003 09:29:31 -0000
@@ -5163,23 +5163,23 @@ $ touch a/sub/deeper/file
 $ ls -gloRF --dired a
   a:
   total 8
-  -rw-r--r--    1        0 Nov  9 18:30 f1
-  -rw-r--r--    1        0 Nov  9 18:30 f2
-  drwxr-xr-x    3     4096 Nov  9 18:30 sub/
-  drwxr-xr-x    2     4096 Nov  9 18:30 sub2/
+  -rw-r--r--  1    0 Dec  3 00:50 f1
+  -rw-r--r--  1    0 Dec  3 00:50 f2
+  drwxr-xr-x  3 4096 Dec  3 00:50 sub/
+  drwxr-xr-x  2 4096 Dec  3 00:50 sub2/
 
   a/sub:
   total 4
-  drwxr-xr-x    2     4096 Nov  9 18:30 deeper/
+  drwxr-xr-x  2 4096 Dec  3 00:50 deeper/
 
   a/sub/deeper:
   total 0
-  -rw-r--r--    1        0 Nov  9 18:30 file
+  -rw-r--r--  1 0 Dec  3 00:50 file
 
   a/sub2:
   total 0
-//DIRED// 55 57 98 100 141 144 186 190 252 258 327 331
-//SUBDIRED// 2 3 195 200 263 275 335 341
+//DIRED// 49 51 86 88 123 126 162 166 222 228 288 292
+//SUBDIRED// 2 3 171 176 233 245 296 302
 //DIRED-OPTIONS// --quoting-style=literal
 @end example
 
@@ -5190,11 +5190,11 @@ The offsets on the @samp{//SUBDIRED//} l
 directory names: @file{a}, @file{a/sub}, @file{a/sub/deeper}, @file{a/sub2}.
 
 Here is an example of how to extract the fifth entry name, @samp{deeper},
-corresponding to the pair of offsets, 252 and 258:
+corresponding to the pair of offsets, 222 and 228:
 
 @example
 $ ls -gloRF --dired a > out
-$ dd bs=1 skip=252 count=6 < out 2>/dev/null; echo
+$ dd bs=1 skip=222 count=6 < out 2>/dev/null; echo
 deeper
 @end example
 
@@ -5208,8 +5208,8 @@ on a file whose name contains special ch
 @example
 $ touch 'a b'
 $ ls -blog --dired 'a b'
-  -rw-r--r--    1        0 Nov  9 18:41 a\ b
-//DIRED// 40 44
+  -rw-r--r--  1 0 Dec  3 00:52 a\ b
+//DIRED// 31 35
 //DIRED-OPTIONS// --quoting-style=escape
 @end example
 
@@ -11417,7 +11417,7 @@ Then you'll see output like this:
 @example
 /:
 total 1023
--rwxr-xr-x    1 0        0         1041745 Aug 16 11:17 ls
+-rwxr-xr-x  1 0 0 1041745 Aug 16 11:17 ls
 @end example
 
 If you want to use a dynamically linked executable, say @command{bash},
@@ -12319,51 +12319,6 @@ $ cal | cut -c 3-5
 @print{} 20
 @print{} 27
 @end example
-
-Cut can also add field separators to fixed width data, using the
address@hidden option.  This can be very useful to fill a
-database:
-
address@hidden [Why] can't that silly total line for directories be switched 
off?
address@hidden
-$ ls -ld ~/* | cut --output-delimiter=, -c1,2-4,5-7,8-10,57- | tee home.cs
address@hidden d,rwx,r-x,r-x,CVS
address@hidden d,rwx,---,---,Mail
address@hidden d,rwx,r-x,r-x,lilypond
address@hidden d,rwx,r-x,r-x,savannah
-$ mysql -e 'create table home \
-  (d char(1),u char(3), g char (3), o char (3), name text)' test
-$ mysqlimport --fields-terminated-by=, test home.cs
address@hidden test.home: Records: 4  Deleted: 0  Skipped: 0  Warnings: 0
-$ mysql -e 'select * from home' test
address@hidden +------+------+------+------+----------+
address@hidden | d    | u    | g    | o    | name     |
address@hidden +------+------+------+------+----------+
address@hidden | d    | rwx  | r-x  | r-x  | CVS      |
address@hidden | d    | rwx  | ---  | ---  | Mail     |
address@hidden | d    | rwx  | r-x  | r-x  | lilypond |
address@hidden | d    | rwx  | r-x  | r-x  | savannah |
address@hidden +------+------+------+------+----------+
address@hidden example
-
-But beware of assumptions.
-The above invocation of @command{ls} assumes that the owner
-and group names are no longer than eight bytes each,
-and that no file has size larger than 99999999 bytes.
-Otherwise, the byte offset of @samp{57} would need to be larger.
-To avoid such problems, suppress output of the owner and group
-names with the @option{-g} and @option{-G} options respectively,
-and add the @option{-h} option to ensure that the representation
-of the size of the file does not exceed the allotted space.
-Finally, note that the width of even the date/time field may change,
-depending on the current locale.  To avoid that, use an option
-like @option{--time-style='+%Y-%m-%d %H:%M:%S'}.
-
-And there's still another problem: if a file has more
-than 999 hard links to it, then that will change the alignment.
-The morale is that it is hard to use fixed byte offsets into
-a line of @command{ls} output.  Use a different tool, like
-find, but with @option{-printf} and carefully chosen format strings.
 
 @node The sort command
 @unnumberedsec The @command{sort} Command
Index: src/ls.c
===================================================================
RCS file: /cvsroot/coreutils/coreutils/src/ls.c,v
retrieving revision 1.347
diff -p -u -r1.347 ls.c
--- src/ls.c    12 Nov 2003 09:23:03 -0000      1.347
+++ src/ls.c    3 Dec 2003 09:59:28 -0000
@@ -128,13 +128,6 @@ int wcwidth ();
    Subtracting doesn't always work, due to overflow.  */
 #define longdiff(a, b) ((a) < (b) ? -1 : (a) > (b))
 
-/* The field width for inode numbers.  On some hosts inode numbers are
-   64 bits, so columns won't line up exactly when a huge inode number
-   is encountered, but in practice 7 digits is usually enough.  */
-#ifndef INODE_DIGITS
-# define INODE_DIGITS 7
-#endif
-
 /* Arrange to make lstat calls go through the wrapper function
    on systems with an lstat function that does not dereference symlinks
    that are specified with a trailing slash.  */
@@ -167,19 +160,6 @@ int rpl_lstat (const char *, struct stat
 # define ST_DM_MODE(Stat_buf) ((Stat_buf).st_mode)
 #endif
 
-#ifndef LOGIN_NAME_MAX
-# if _POSIX_LOGIN_NAME_MAX
-#  define LOGIN_NAME_MAX _POSIX_LOGIN_NAME_MAX
-# else
-#  define LOGIN_NAME_MAX 17
-# endif
-#endif
-
-/* The maximum length of a string representation of a user or group ID,
-   not counting any terminating NUL byte.  */
-#define ID_LENGTH_MAX \
-  MAX (LOGIN_NAME_MAX - 1, LONGEST_HUMAN_READABLE)
-
 enum filetype
   {
     unknown DT_INIT (DT_UNKNOWN),
@@ -269,6 +249,8 @@ static void print_current_files (void);
 static void print_dir (const char *name, const char *realname);
 static void print_file_name_and_frills (const struct fileinfo *f);
 static void print_horizontal (void);
+static int format_user_width (uid_t u);
+static int format_group_width (gid_t g);
 static void print_long_format (const struct fileinfo *f);
 static void print_many_per_line (void);
 static void print_name_with_quoting (const char *p, mode_t mode,
@@ -348,10 +330,19 @@ static struct pending *pending_dirs;
 static time_t current_time = TYPE_MINIMUM (time_t);
 static int current_time_ns = -1;
 
-/* The number of digits to use for block sizes.
-   4, or more if needed for bigger numbers.  */
-
-static int block_size_size;
+/* The number of bytes to use for columns containing inode numbers,
+   block sizes, link counts, owners, groups, authors, major device
+   numbers, minor device numbers, and file sizes, respectively.  */
+
+static int inode_number_width;
+static int block_size_width;
+static int nlink_width;
+static int owner_width;
+static int group_width;
+static int author_width;
+static int major_device_number_width;
+static int minor_device_number_width;
+static int file_size_width;
 
 /* Option flags */
 
@@ -2286,6 +2277,16 @@ file_interesting (const struct dirent *n
   return 0;
 }
 
+/* POSIX requires that a file size be printed without a sign, even
+   when negative.  Assume the typical case where negative sizes are
+   actually positive values that have wrapped around.  */
+
+static uintmax_t
+unsigned_file_size (off_t size)
+{
+  return size + (size < 0) * ((uintmax_t) OFF_T_MAX - OFF_T_MIN + 1);
+}
+
 /* Enter and remove entries in the table `files'.  */
 
 /* Empty the table of files. */
@@ -2303,7 +2304,15 @@ clear_files (void)
     }
 
   files_index = 0;
-  block_size_size = 4;
+  inode_number_width = 0;
+  block_size_width = 0;
+  nlink_width = 0;
+  owner_width = 0;
+  group_width = 0;
+  author_width = 0;
+  major_device_number_width = 0;
+  minor_device_number_width = 0;
+  file_size_width = 0;
 }
 
 /* Add a file to the current table of files.
@@ -2316,6 +2325,7 @@ gobble_file (const char *name, enum file
 {
   register uintmax_t blocks;
   register char *path;
+  register struct fileinfo *f;
 
   if (files_index == nfiles)
     {
@@ -2323,9 +2333,10 @@ gobble_file (const char *name, enum file
       nfiles *= 2;
     }
 
-  files[files_index].linkname = 0;
-  files[files_index].linkmode = 0;
-  files[files_index].linkok = 0;
+  f = &files[files_index];
+  f->linkname = 0;
+  f->linkmode = 0;
+  f->linkok = 0;
 
   if (explicit_arg
       || format_needs_stat
@@ -2362,7 +2373,7 @@ gobble_file (const char *name, enum file
       switch (dereference)
        {
        case DEREF_ALWAYS:
-         err = stat (path, &files[files_index].stat);
+         err = stat (path, &f->stat);
          break;
 
        case DEREF_COMMAND_LINE_ARGUMENTS:
@@ -2370,14 +2381,14 @@ gobble_file (const char *name, enum file
          if (explicit_arg)
            {
              int need_lstat;
-             err = stat (path, &files[files_index].stat);
+             err = stat (path, &f->stat);
 
              if (dereference == DEREF_COMMAND_LINE_ARGUMENTS)
                break;
 
              need_lstat = (err < 0
                            ? errno == ENOENT
-                           : ! S_ISDIR (files[files_index].stat.st_mode));
+                           : ! S_ISDIR (f->stat.st_mode));
              if (!need_lstat)
                break;
 
@@ -2388,7 +2399,7 @@ gobble_file (const char *name, enum file
            }
 
        default: /* DEREF_NEVER */
-         err = lstat (path, &files[files_index].stat);
+         err = lstat (path, &f->stat);
          break;
        }
 
@@ -2402,21 +2413,21 @@ gobble_file (const char *name, enum file
 #if HAVE_ACL
       if (format == long_format)
        {
-         int n = file_has_acl (path, &files[files_index].stat);
-         files[files_index].have_acl = (0 < n);
+         int n = file_has_acl (path, &f->stat);
+         f->have_acl = (0 < n);
          if (n < 0)
            error (0, errno, "%s", quotearg_colon (path));
        }
 #endif
 
-      if (S_ISLNK (files[files_index].stat.st_mode)
+      if (S_ISLNK (f->stat.st_mode)
          && (format == long_format || check_symlink_color))
        {
          char *linkpath;
          struct stat linkstats;
 
-         get_link_name (path, &files[files_index]);
-         linkpath = make_link_path (path, files[files_index].linkname);
+         get_link_name (path, f);
+         linkpath = make_link_path (path, f->linkname);
 
          /* Avoid following symbolic links when possible, ie, when
             they won't be traced and when no indicator is needed. */
@@ -2424,7 +2435,7 @@ gobble_file (const char *name, enum file
              && (indicator_style != none || check_symlink_color)
              && stat (linkpath, &linkstats) == 0)
            {
-             files[files_index].linkok = 1;
+             f->linkok = 1;
 
              /* Symbolic links to directories that are mentioned on the
                 command line are automatically traced if not being
@@ -2434,45 +2445,103 @@ gobble_file (const char *name, enum file
                {
                  /* Get the linked-to file's mode for the filetype indicator
                     in long listings.  */
-                 files[files_index].linkmode = linkstats.st_mode;
-                 files[files_index].linkok = 1;
+                 f->linkmode = linkstats.st_mode;
+                 f->linkok = 1;
                }
            }
          if (linkpath)
            free (linkpath);
        }
 
-      if (S_ISLNK (files[files_index].stat.st_mode))
-       files[files_index].filetype = symbolic_link;
-      else if (S_ISDIR (files[files_index].stat.st_mode))
+      if (S_ISLNK (f->stat.st_mode))
+       f->filetype = symbolic_link;
+      else if (S_ISDIR (f->stat.st_mode))
        {
          if (explicit_arg && !immediate_dirs)
-           files[files_index].filetype = arg_directory;
+           f->filetype = arg_directory;
          else
-           files[files_index].filetype = directory;
+           f->filetype = directory;
        }
       else
-       files[files_index].filetype = normal;
+       f->filetype = normal;
 
-      blocks = ST_NBLOCKS (files[files_index].stat);
+      {
+       char buf[INT_BUFSIZE_BOUND (uintmax_t)];
+       int len = strlen (umaxtostr (f->stat.st_ino, buf));
+       if (inode_number_width < len)
+         inode_number_width = len;
+      }
+
+      blocks = ST_NBLOCKS (f->stat);
       {
        char buf[LONGEST_HUMAN_READABLE + 1];
        int len = strlen (human_readable (blocks, buf, human_output_opts,
                                          ST_NBLOCKSIZE, output_block_size));
-       if (block_size_size < len)
-         block_size_size = len < 7 ? len : 7;
+       if (block_size_width < len)
+         block_size_width = len;
+      }
+
+      if (print_owner)
+       {
+         int len = format_user_width (f->stat.st_uid);
+         if (owner_width < len)
+           owner_width = len;
+       }
+
+      if (print_group)
+       {
+         int len = format_group_width (f->stat.st_gid);
+         if (group_width < len)
+           group_width = len;
+       }
+
+      if (print_author)
+       {
+         int len = format_user_width (f->stat.st_uid);
+         if (author_width < len)
+           author_width = len;
+       }
+
+      {
+       char buf[INT_BUFSIZE_BOUND (uintmax_t)];
+       int len = strlen (umaxtostr (f->stat.st_nlink, buf));
+       if (nlink_width < len)
+         nlink_width = len;
       }
+
+      if (S_ISCHR (f->stat.st_mode) || S_ISBLK (f->stat.st_mode))
+       {
+         char buf[INT_BUFSIZE_BOUND (uintmax_t)];
+         int len = strlen (umaxtostr (major (f->stat.st_rdev), buf));
+         if (major_device_number_width < len)
+           major_device_number_width = len;
+         len = strlen (umaxtostr (minor (f->stat.st_rdev), buf));
+         if (minor_device_number_width < len)
+           minor_device_number_width = len;
+         len = major_device_number_width + 2 + minor_device_number_width;
+         if (file_size_width < len)
+           file_size_width = len;
+       }
+      else
+       {
+         char buf[LONGEST_HUMAN_READABLE + 1];
+         uintmax_t size = unsigned_file_size (f->stat.st_size);
+         int len = strlen (human_readable (size, buf, human_output_opts,
+                                           1, file_output_block_size));
+         if (file_size_width < len)
+           file_size_width = len;
+       }
     }
   else
     {
-      files[files_index].filetype = type;
+      f->filetype = type;
 #if HAVE_STRUCT_DIRENT_D_TYPE
-      files[files_index].stat.st_mode = DTTOIF (type);
+      f->stat.st_mode = DTTOIF (type);
 #endif
       blocks = 0;
     }
 
-  files[files_index].name = xstrdup (name);
+  f->name = xstrdup (name);
   files_index++;
 
   return blocks;
@@ -2902,21 +2971,77 @@ get_current_time (void)
   current_time_ns = 999999999;
 }
 
-/* Format into BUFFER the name or id of the user with id U.  Return
-   the length of the formatted buffer, not counting the terminating
-   null.  */
+/* Print the name or id of the user with id U, using a print width of
+   WIDTH.  */
 
-static size_t
-format_user (char *buffer, uid_t u)
+static void
+format_user (uid_t u, int width)
 {
   char const *name = (numeric_ids ? NULL : getuser (u));
   if (name)
-    sprintf (buffer, "%-8s ", name);
+    printf ("%-*s ", width, name);
+  else
+    printf ("%*lu ", width, (unsigned long int) u);
+  dired_pos += width + 1;
+}
+
+/* Likewise, for groups.  */
+
+static void
+format_group (gid_t g, int width)
+{
+  char const *name = (numeric_ids ? NULL : getgroup (g));
+  if (name)
+    printf ("%-*s ", width, name);
   else
-    sprintf (buffer, "%-8lu ", (unsigned long int) u);
-  return strlen (buffer);
+    printf ("%*lu ", width, (unsigned long int) g);
+  dired_pos += width;
+  dired_pos++;
 }
 
+/* Return the number of bytes that format_user will print.  */
+
+static int
+format_user_width (uid_t u)
+{
+  char const *name = (numeric_ids ? NULL : getuser (u));
+  char buf[INT_BUFSIZE_BOUND (unsigned long int)];
+  size_t len;
+
+  if (! name)
+    {
+      sprintf (buf, "%lu", (unsigned long int) u);
+      name = buf;
+    }
+
+  len = strlen (name);
+  if (INT_MAX < len)
+    error (EXIT_FAILURE, 0, _("User name too long"));
+  return len;
+}
+
+/* Likewise, for groups.  */
+
+static int
+format_group_width (gid_t g)
+{
+  char const *name = (numeric_ids ? NULL : getgroup (g));
+  char buf[INT_BUFSIZE_BOUND (unsigned long int)];
+  size_t len;
+
+  if (! name)
+    {
+      sprintf (buf, "%lu", (unsigned long int) g);
+      name = buf;
+    }
+
+  len = strlen (name);
+  if (INT_MAX < len)
+    error (EXIT_FAILURE, 0, _("Group name too long"));
+  return len;
+}
+
+
 /* Print information about F in long format.  */
 
 static void
@@ -2927,11 +3052,8 @@ print_long_format (const struct fileinfo
     [LONGEST_HUMAN_READABLE + 1                /* inode */
      + LONGEST_HUMAN_READABLE + 1      /* size in blocks */
      + sizeof (modebuf) - 1 + 1                /* mode string */
-     + LONGEST_HUMAN_READABLE + 1      /* st_nlink */
-     + ID_LENGTH_MAX + 1               /* owner name */
-     + ID_LENGTH_MAX + 1               /* group name */
-     + ID_LENGTH_MAX + 1               /* author name */
-     + LONGEST_HUMAN_READABLE + 1      /* major device number */
+     + INT_BUFSIZE_BOUND (uintmax_t)   /* st_nlink */
+     + LONGEST_HUMAN_READABLE + 2      /* major device number */
      + LONGEST_HUMAN_READABLE + 1      /* minor device number */
      + 35 + 1  /* usual length of time/date -- may be longer; see below */
      ];
@@ -2971,61 +3093,71 @@ print_long_format (const struct fileinfo
 
   if (print_inode)
     {
-      char hbuf[LONGEST_HUMAN_READABLE + 1];
-      sprintf (p, "%*s ", INODE_DIGITS, umaxtostr (f->stat.st_ino, hbuf));
-      p += strlen (p);
+      char hbuf[INT_BUFSIZE_BOUND (uintmax_t)];
+      sprintf (p, "%*s ", inode_number_width,
+              umaxtostr (f->stat.st_ino, hbuf));
+      p += inode_number_width + 1;
     }
 
   if (print_block_size)
     {
       char hbuf[LONGEST_HUMAN_READABLE + 1];
-      sprintf (p, "%*s ", block_size_size,
+      sprintf (p, "%*s ", block_size_width,
               human_readable (ST_NBLOCKS (f->stat), hbuf, human_output_opts,
                               ST_NBLOCKSIZE, output_block_size));
-      p += strlen (p);
+      p += block_size_width + 1;
     }
 
   /* The last byte of the mode string is the POSIX
      "optional alternate access method flag".  */
-  sprintf (p, "%s %3lu ", modebuf, (unsigned long int) f->stat.st_nlink);
-  p += strlen (p);
+  {
+    char hbuf[INT_BUFSIZE_BOUND (uintmax_t)];
+    sprintf (p, "%s %*s ", modebuf, nlink_width,
+            umaxtostr (f->stat.st_nlink, hbuf));
+  }
+  p += sizeof modebuf + nlink_width + 1;
 
-  if (print_owner)
-    p += format_user (p, f->stat.st_uid);
+  DIRED_INDENT ();
 
-  if (print_group)
+  if (print_owner | print_group | print_author)
     {
-      char const *group_name = (numeric_ids ? NULL : getgroup 
(f->stat.st_gid));
-      if (group_name)
-       sprintf (p, "%-8s ", group_name);
-      else
-       sprintf (p, "%-8lu ", (unsigned long int) f->stat.st_gid);
-      p += strlen (p);
-    }
+      DIRED_FPUTS (buf, stdout, p - buf);
+
+      if (print_owner)
+       format_user (f->stat.st_uid, owner_width);
+
+      if (print_group)
+       format_group (f->stat.st_gid, group_width);
 
-  if (print_author)
-    p += format_user (p, f->stat.st_author);
+      if (print_author)
+       format_user (f->stat.st_author, author_width);
+
+      p = buf;
+    }
 
   if (S_ISCHR (f->stat.st_mode) || S_ISBLK (f->stat.st_mode))
-    sprintf (p, "%3lu, %3lu ",
-            (unsigned long int) major (f->stat.st_rdev),
-            (unsigned long int) minor (f->stat.st_rdev));
+    {
+      char majorbuf[INT_BUFSIZE_BOUND (uintmax_t)];
+      char minorbuf[INT_BUFSIZE_BOUND (uintmax_t)];
+      int blanks_width = (file_size_width
+                         - (major_device_number_width + 2
+                            + minor_device_number_width));
+      sprintf (p, "%*s, %*s ",
+              major_device_number_width + MAX (0, blanks_width),
+              umaxtostr (major (f->stat.st_rdev), majorbuf),
+              minor_device_number_width,
+              umaxtostr (minor (f->stat.st_rdev), minorbuf));
+    }
   else
     {
       char hbuf[LONGEST_HUMAN_READABLE + 1];
-      uintmax_t size = f->stat.st_size;
-
-      /* POSIX requires that the size be printed without a sign, even
-        when negative.  Assume the typical case where negative sizes
-        are actually positive values that have wrapped around.  */
-      size += (f->stat.st_size < 0) * ((uintmax_t) OFF_T_MAX - OFF_T_MIN + 1);
-
-      sprintf (p, "%8s ",
+      uintmax_t size = unsigned_file_size (f->stat.st_size);
+      sprintf (p, "%*s ", file_size_width,
               human_readable (size, hbuf, human_output_opts,
                               1, file_output_block_size));
     }
 
-  p += strlen (p);
+  p += file_size_width + 1;
 
   if ((when_local = localtime (&when)))
     {
@@ -3088,7 +3220,6 @@ print_long_format (const struct fileinfo
       p += strlen (p);
     }
 
-  DIRED_INDENT ();
   DIRED_FPUTS (buf, stdout, p - buf);
   print_name_with_quoting (f->name, FILE_OR_LINK_MODE (f), f->linkok,
                           &dired_obstack);
@@ -3321,10 +3452,10 @@ print_file_name_and_frills (const struct
   char buf[MAX (LONGEST_HUMAN_READABLE + 1, INT_BUFSIZE_BOUND (uintmax_t))];
 
   if (print_inode)
-    printf ("%*s ", INODE_DIGITS, umaxtostr (f->stat.st_ino, buf));
+    printf ("%*s ", inode_number_width, umaxtostr (f->stat.st_ino, buf));
 
   if (print_block_size)
-    printf ("%*s ", block_size_size,
+    printf ("%*s ", block_size_width,
            human_readable (ST_NBLOCKS (f->stat), buf, human_output_opts,
                            ST_NBLOCKSIZE, output_block_size));
 
@@ -3458,10 +3589,10 @@ length_of_file_name_and_frills (const st
   size_t name_width;
 
   if (print_inode)
-    len += INODE_DIGITS + 1;
+    len += inode_number_width + 1;
 
   if (print_block_size)
-    len += 1 + block_size_size;
+    len += block_size_width + 1;
 
   quote_name (NULL, f->name, filename_quoting_options, &name_width);
   len += name_width;
Index: tests/cp/same-file
===================================================================
RCS file: /cvsroot/coreutils/coreutils/tests/cp/same-file,v
retrieving revision 1.37
diff -p -u -r1.37 same-file
--- tests/cp/same-file  14 May 2003 06:26:34 -0000      1.37
+++ tests/cp/same-file  3 Dec 2003 09:29:42 -0000
@@ -74,11 +74,10 @@ for args in 'foo symlink' 'symlink foo' 
        # and put brackets around the output.
        test -s _err && echo "[`sed 's/^[^:][^:]*:/cp:/' _err`]"
        # Strip off all but the file names.
-       # Omit the variable-width owner and group names.
        ls="`ls -gG --ignore=_err . \
            | sed \
                -e '/^total /d' \
-               -e 's/^......................................//'`"
+               -e 's/^[^ ]*  *[^ ]*  *[^ ]*  *[^ ]*  *[^ ]*  *[^ ]*  *//'`"
        echo "($ls)"
        # Make sure the original is unchanged and that
        # the destination is a copy.
Index: tests/mv/part-symlink
===================================================================
RCS file: /cvsroot/coreutils/coreutils/tests/mv/part-symlink,v
retrieving revision 1.16
diff -p -u -r1.16 part-symlink
--- tests/mv/part-symlink       14 May 2003 06:27:12 -0000      1.16
+++ tests/mv/part-symlink       3 Dec 2003 09:29:43 -0000
@@ -108,13 +108,13 @@ for copy in cp mv; do
                  -e '/^total /d' \
                  -e s,$other_partition_tmpdir/,, \
                  -e s,$pwd_tmp/,, \
-                 -e 's/^......................................//'`"
+                 -e 's/^[^ ]*  *[^ ]*  *[^ ]*  *[^ ]*  *[^ ]*  *[^ ]*  *//'`"
          ls2="`cd $other_partition_tmpdir && ls -gG --ignore=.err . \
              | sed \
                  -e '/^total /d' \
                  -e s,$other_partition_tmpdir/,, \
                  -e s,$pwd_tmp/,, \
-                 -e 's/^......................................//'`"
+                 -e 's/^[^ ]*  *[^ ]*  *[^ ]*  *[^ ]*  *[^ ]*  *[^ ]*  *//'`"
          echo "($ls) ($ls2)"
 
          # If the command failed, then it must not have changed the files.




reply via email to

[Prev in Thread] Current Thread [Next in Thread]