svn commit: r351413 - head/usr.bin/last

Conrad Meyer cem at freebsd.org
Fri Aug 23 03:01:32 UTC 2019


Hi Eugene,

Should this be done more generally?  Last time I looked it seemed like
libxo was completely locale-unaware and just assumed all input was
UTF-8.  It might make more sense to have libxo take locale into
account when formatting %s strings.

Best,
Conrad

On Thu, Aug 22, 2019 at 6:25 PM Eugene Grosbein <eugen at freebsd.org> wrote:
>
> Author: eugen
> Date: Fri Aug 23 01:25:38 2019
> New Revision: 351413
> URL: https://svnweb.freebsd.org/changeset/base/351413
>
> Log:
>   last(1): unbreak for 8-bit locales
>
>   Ouput format of last(1) is broken for non UTF-8 locales
>   since it got libxo(3) support. It uses strftime(3) that produces
>   non UTF-8 strings passed to xo_emit(3) with wrong %s format -
>   it should be %hs in this case, so xo_emit(3) produces empty output.
>
>   This change is basically no-op when locale is of UTF-8 type,
>   f.e. en_GB.UTF-8 or ru_RU.UTF-8 or sr_RS.UTF-8 at latin.
>   It fixes output for other locales.
>
>   MFC after:    2 weeks
>
> Modified:
>   head/usr.bin/last/last.c
>
> Modified: head/usr.bin/last/last.c
> ==============================================================================
> --- head/usr.bin/last/last.c    Fri Aug 23 01:16:12 2019        (r351412)
> +++ head/usr.bin/last/last.c    Fri Aug 23 01:25:38 2019        (r351413)
> @@ -93,6 +93,7 @@ static time_t currentout;                     /* current logout value */
>  static long    maxrec;                         /* records to display */
>  static const   char *file = NULL;              /* utx.log file */
>  static int     sflag = 0;                      /* show delta in seconds */
> +static int     utf8flag;                       /* current locale is UTF-8 */
>  static int     width = 5;                      /* show seconds in delta */
>  static int     yflag;                          /* show year */
>  static int      d_first;
> @@ -103,6 +104,7 @@ static time_t       snaptime;                       /* if != 0, we will only
>                                                  */
>
>  static void     addarg(int, char *);
> +static const char *ctf(const char *);
>  static time_t   dateconv(char *);
>  static void     doentry(struct utmpx *);
>  static void     hostconv(char *);
> @@ -112,6 +114,31 @@ static int  want(struct utmpx *);
>  static void     usage(void);
>  static void     wtmp(void);
>
> +static const char*
> +ctf(const char *fmt) {
> +       static char  buf[31];
> +       const char  *src, *end;
> +       char        *dst;
> +
> +       if (utf8flag)
> +               return (fmt);
> +
> +       end = buf + sizeof(buf);
> +       for (src = fmt, dst = buf; dst < end; *dst++ = *src++) {
> +               if (*src == '\0') {
> +                       *dst = '\0';
> +                       break;
> +               } else if (*src == '%' && *(src+1) == 's') {
> +                       *dst++ = '%';
> +                       *dst++ = 'h';
> +                       *dst++ = 's';
> +                       strlcpy(dst, src+2, end - dst);
> +                       return (buf);
> +               }
> +       }
> +       return (buf);
> +}
> +
>  static void
>  usage(void)
>  {
> @@ -130,6 +157,9 @@ main(int argc, char *argv[])
>         (void) setlocale(LC_TIME, "");
>         d_first = (*nl_langinfo(D_MD_ORDER) == 'd');
>
> +       (void) setlocale(LC_CTYPE, "");
> +       utf8flag = (strcmp(nl_langinfo(CODESET), "UTF-8") == 0);
> +
>         argc = xo_parse_args(argc, argv);
>         if (argc < 0)
>                 exit(1);
> @@ -262,7 +292,7 @@ wtmp(void)
>         (void) strftime(ct, sizeof(ct), "%+", tm);
>         xo_emit("\n{:utxdb/%s}", (file == NULL) ? "utx.log" : file);
>         xo_attr("seconds", "%lu", (unsigned long) t);
> -       xo_emit(" begins {:begins/%s}\n", ct);
> +       xo_emit(ctf(" begins {:begins/%s}\n"), ct);
>         xo_close_container("last-information");
>  }
>
> @@ -379,7 +409,7 @@ printentry(struct utmpx *bp, struct idtab *tt)
>                 break;
>         }
>         xo_attr("seconds", "%lu", (unsigned long)t);
> -       xo_emit(" {:login-time/%s%c/%s}", ct, tt == NULL ? '\n' : ' ');
> +       xo_emit(ctf(" {:login-time/%s%c/%s}"), ct, tt == NULL ? '\n' : ' ');
>         if (tt == NULL)
>                 goto end;
>         if (!tt->logout) {
> @@ -393,7 +423,7 @@ printentry(struct utmpx *bp, struct idtab *tt)
>                 tm = localtime(&tt->logout);
>                 (void) strftime(ct, sizeof(ct), "%R", tm);
>                 xo_attr("seconds", "%lu", (unsigned long)tt->logout);
> -               xo_emit("- {:logout-time/%s}", ct);
> +               xo_emit(ctf("- {:logout-time/%s}"), ct);
>         }
>         delta = tt->logout - bp->ut_tv.tv_sec;
>         xo_attr("seconds", "%ld", (long)delta);
> @@ -403,9 +433,9 @@ printentry(struct utmpx *bp, struct idtab *tt)
>                 tm = gmtime(&delta);
>                 (void) strftime(ct, sizeof(ct), width >= 8 ? "%T" : "%R", tm);
>                 if (delta < 86400)
> -                       xo_emit("  ({:session-length/%s})\n", ct);
> +                       xo_emit(ctf("  ({:session-length/%s})\n"), ct);
>                 else
> -                       xo_emit(" ({:session-length/%ld+%s})\n",
> +                       xo_emit(ctf(" ({:session-length/%ld+%s})\n"),
>                             (long)delta / 86400, ct);
>         }
>
>


More information about the svn-src-head mailing list