From: Jim Meyering Date: Tue, 22 Jun 2004 12:50:01 +0000 (+0000) Subject: Fix bug: GNU 'ls' didn't count columns correctly if user or group X-Git-Tag: v5.3.0~1275 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e1de0b295ea1fa7fcf26d93b27c95d5b5476cfe8;p=thirdparty%2Fcoreutils.git 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. --- diff --git a/src/ls.c b/src/ls.c index b986e68c14..d8fe9222f6 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); }