diff options
author | Jim Meyering <jim@meyering.net> | 2004-06-22 12:50:01 +0000 |
---|---|---|
committer | Jim Meyering <jim@meyering.net> | 2004-06-22 12:50:01 +0000 |
commit | e1de0b295ea1fa7fcf26d93b27c95d5b5476cfe8 (patch) | |
tree | c832a07e4c824491b6cd346ffb3da58b78f6d93d | |
parent | c18f06d7b0e7282400c03d5d3294d59ecd197be3 (diff) | |
download | coreutils-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.
-rw-r--r-- | src/ls.c | 99 |
1 files changed, 55 insertions, 44 deletions
@@ -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); } |