The 2004-06-19 fix for who and pinky was incomplete, as ctime
authorJim Meyering <jim@meyering.net>
Tue, 22 Jun 2004 14:56:46 +0000 (14:56 +0000)
committerJim Meyering <jim@meyering.net>
Tue, 22 Jun 2004 14:56:46 +0000 (14:56 +0000)
has undefined behavior if the year precedes -999 or follows 9999.
Since we have to stop using ctime anyway, we might as well use
strftime and fix the FIXME, and support internationalized dates.

Include "hard-locale.h".
(time_format, time_format_width): New vars.
(time_string, print_line): Use them.
(main): Set them.
(time_string): Use localtime + strftime instead of
ctime, to avoid problems with years before -999 or after 9999.

src/who.c

index f8da4737e99c1a08638ab83123d64f7be53540d6..49209a562911bd3ba3bb318e14b7b34c50e4ded0 100644 (file)
--- a/src/who.c
+++ b/src/who.c
@@ -33,6 +33,7 @@
 
 #include "readutmp.h"
 #include "error.h"
+#include "hard-locale.h"
 #include "inttostr.h"
 #include "quote.h"
 #include "vasprintf.h"
@@ -168,6 +169,11 @@ static int need_users;
 /* If nonzero, display info only for the controlling tty */
 static int my_line_only;
 
+/* The strftime format to use for login times, and its expected
+   output width.  */
+static char const *time_format;
+static int time_format_width;
+
 /* for long options with no corresponding short option, use enum */
 enum
 {
@@ -222,31 +228,28 @@ idle_string (time_t when)
   return _(" old ");
 }
 
-/* Return a standard time string, "mon dd hh:mm"
-   FIXME: handle localization */
+/* Return a time string.  */
 static const char *
 time_string (const STRUCT_UTMP *utmp_ent)
 {
+  static char buf[INT_STRLEN_BOUND (intmax_t) + sizeof "-%m-%d %H:%M"];
+
   /* Don't take the address of UT_TIME_MEMBER directly.
      Ulrich Drepper wrote:
      ``... GNU libc (and perhaps other libcs as well) have extended
      utmp file formats which do not use a simple time_t ut_time field.
      In glibc, ut_time is a macro which selects for backward compatibility
      the tv_sec member of a struct timeval value.''  */
-  time_t tm = UT_TIME_MEMBER (utmp_ent);
+  time_t t = UT_TIME_MEMBER (utmp_ent);
+  struct tm *tmp = localtime (&t);
 
-  char *ptr = ctime (&tm);
-  if (ptr)
+  if (tmp)
     {
-      ptr += 4;
-      ptr[12] = '\0';
+      strftime (buf, sizeof buf, time_format, tmp);
+      return buf;
     }
   else
-    {
-      static char buf[INT_BUFSIZE_BOUND (intmax_t)];
-      ptr = (TYPE_SIGNED (time_t) ? imaxtostr (tm, buf) : umaxtostr (tm, buf));
-    }
-  return ptr;
+    return TYPE_SIGNED (time_t) ? imaxtostr (t, buf) : umaxtostr (t, buf);
 }
 
 /* Print formatted output line. Uses mostly arbitrary field sizes, probably
@@ -286,7 +289,7 @@ print_line (const char *user, const char state, const char *line,
                  "%-8s"
                  "%s"
                  " %-12s"
-                 " %-12s"
+                 " %-*s"
                  "%s"
                  "%s"
                  " %-8s"
@@ -295,6 +298,7 @@ print_line (const char *user, const char state, const char *line,
                  user ? user : "   .",
                  include_mesg ? mesg : "",
                  line,
+                 time_format_width,
                  time_str,
                  x_idle,
                  x_pid,
@@ -796,6 +800,17 @@ main (int argc, char **argv)
       short_output = 0;
     }
 
+  if (hard_locale (LC_TIME))
+    {
+      time_format = "%Y-%m-%d %H:%M";
+      time_format_width = 4 + 1 + 2 + 1 + 2 + 1 + 2 + 1 + 2;
+    }
+  else
+    {
+      time_format = "%b %e %H:%M";
+      time_format_width = 3 + 1 + 2 + 1 + 2 + 1 + 2;
+    }
+
   switch (argc - optind)
     {
     case -1: