summaryrefslogtreecommitdiff
path: root/src/ls.c
diff options
context:
space:
mode:
authorJim Meyering <jim@meyering.net>2004-06-22 12:50:01 +0000
committerJim Meyering <jim@meyering.net>2004-06-22 12:50:01 +0000
commite1de0b295ea1fa7fcf26d93b27c95d5b5476cfe8 (patch)
treec832a07e4c824491b6cd346ffb3da58b78f6d93d /src/ls.c
parentc18f06d7b0e7282400c03d5d3294d59ecd197be3 (diff)
downloadcoreutils-e1de0b295ea1fa7fcf26d93b27c95d5b5476cfe8.tar.xz
Fix bug: GNU 'ls' didn't count columns correctly if user or group
names contained multibyte characters where the column count differed from the byte count. This patch also corrects some comments. (format_user_or_group): New function, which counts columns correctly. (format_user, format_group): Use it. (format_user_or_group_width): New function, which counts columns correctly. (format_user_width, format_group_width): Use it.
Diffstat (limited to 'src/ls.c')
-rw-r--r--src/ls.c99
1 files changed, 55 insertions, 44 deletions
diff --git a/src/ls.c b/src/ls.c
index b986e68c1..d8fe9222f 100644
--- a/src/ls.c
+++ b/src/ls.c
@@ -330,7 +330,7 @@ static struct pending *pending_dirs;
static time_t current_time = TYPE_MINIMUM (time_t);
static int current_time_ns = -1;
-/* The number of bytes to use for columns containing inode numbers,
+/* The number of columns to use for columns containing inode numbers,
block sizes, link counts, owners, groups, authors, major device
numbers, minor device numbers, and file sizes, respectively. */
@@ -804,14 +804,14 @@ static struct column_info *column_info;
/* Maximum number of columns ever possible for this display. */
static size_t max_idx;
-/* The minimum width of a colum is 3: 1 character for the name and 2
+/* The minimum width of a column is 3: 1 character for the name and 2
for the separating white space. */
#define MIN_COLUMN_WIDTH 3
/* This zero-based index is used solely with the --dired option.
When that option is in effect, this counter is incremented for each
- character of output generated by this program so that the beginning
+ byte of output generated by this program so that the beginning
and ending indices (in that output) of every file name can be recorded
and later output themselves. */
static size_t dired_pos;
@@ -3055,19 +3055,44 @@ get_current_time (void)
current_time_ns = 999999999;
}
+/* Print the user or group name NAME, with numeric id ID, using a
+ print width of WIDTH columns. */
+
+static void
+format_user_or_group (char const *name, unsigned long int id, int width)
+{
+ size_t len;
+
+ if (name)
+ {
+ /* The output column count may differ from the byte count.
+ Adjust for this, but don't output garbage if integer overflow
+ occurs during adjustment. */
+ len = strlen (name);
+ width -= mbswidth (name, 0);
+ width += len;
+ if (width < 0)
+ width = 0;
+ printf ("%-*s ", width, name);
+ if (len < width)
+ len = width;
+ }
+ else
+ {
+ printf ("%*lu ", width, id);
+ len = width;
+ }
+
+ dired_pos += len + 1;
+}
+
/* Print the name or id of the user with id U, using a print width of
WIDTH. */
static void
format_user (uid_t u, int width)
{
- char const *name = (numeric_ids ? NULL : getuser (u));
- if (name)
- printf ("%-*s ", width, name);
- else
- printf ("%*lu ", width, (unsigned long int) u);
- dired_pos += width;
- dired_pos++;
+ format_user_or_group (numeric_ids ? NULL : getuser (u), u, width);
}
/* Likewise, for groups. */
@@ -3075,34 +3100,33 @@ format_user (uid_t u, int width)
static void
format_group (gid_t g, int width)
{
- char const *name = (numeric_ids ? NULL : getgroup (g));
- if (name)
- printf ("%-*s ", width, name);
- else
- printf ("%*lu ", width, (unsigned long int) g);
- dired_pos += width;
- dired_pos++;
+ format_user_or_group (numeric_ids ? NULL : getgroup (g), g, width);
}
-/* Return the number of bytes that format_user will print. */
+/* Return the number of columns that format_user_or_group will print. */
static int
-format_user_width (uid_t u)
+format_user_or_group_width (char const *name, unsigned long int id)
{
- char const *name = (numeric_ids ? NULL : getuser (u));
- char buf[INT_BUFSIZE_BOUND (unsigned long int)];
- size_t len;
-
- if (! name)
+ if (name)
+ {
+ int len = mbswidth (name, 0);
+ return MAX (0, len);
+ }
+ else
{
- sprintf (buf, "%lu", (unsigned long int) u);
- name = buf;
+ char buf[INT_BUFSIZE_BOUND (unsigned long int)];
+ sprintf (buf, "%lu", id);
+ return strlen (buf);
}
+}
- len = strlen (name);
- if (INT_MAX < len)
- error (EXIT_FAILURE, 0, _("User name too long"));
- return len;
+/* Return the number of columns that format_user will print. */
+
+static int
+format_user_width (uid_t u)
+{
+ return format_user_or_group_width (numeric_ids ? NULL : getuser (u), u);
}
/* Likewise, for groups. */
@@ -3110,20 +3134,7 @@ format_user_width (uid_t u)
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;
+ return format_user_or_group_width (numeric_ids ? NULL : getgroup (g), g);
}