[PATCH 1/1] paint visual host key with unicode box-drawing characters

Roland Mainz roland.mainz at nrubsig.org
Wed Jul 8 00:25:25 AEST 2015


On Mon, Jul 6, 2015 at 12:05 PM, Christian Hesse <list at eworm.de> wrote:
> From: Christian Hesse <mail at eworm.de>
>
> Signed-off-by: Christian Hesse <mail at eworm.de>
> ---
>  sshkey.c | 47 ++++++++++++++++++++++++++++++++++++-----------
>  1 file changed, 36 insertions(+), 11 deletions(-)
>
> diff --git a/sshkey.c b/sshkey.c
> index cfe5980..47511c2 100644
> --- a/sshkey.c
> +++ b/sshkey.c
> @@ -44,6 +44,9 @@
>  #include <stdio.h>
>  #include <string.h>
>  #include <resolv.h>
> +#ifdef HAVE_LOCALE_H
> +#include <locale.h>
> +#endif /* HAVE_LOCALE_H */
>  #ifdef HAVE_UTIL_H
>  #include <util.h>
>  #endif /* HAVE_UTIL_H */
> @@ -1088,6 +1091,12 @@ fingerprint_randomart(const char *alg, u_char *dgst_raw, size_t dgst_raw_len,
>          * Chars to be used after each other every time the worm
>          * intersects with itself.  Matter of taste.
>          */
> +#ifdef HAVE_LOCALE_H
> +       char    *locale;
> +       char    *border_utf8[]  = { "┏", "━", "┓", "┃", "┗", "┛" };
> +#endif
> +       char    *border_ascii[] = { "+", "-", "+", "|", "+", "+" };
> +       char   **border;
>         char    *augmentation_string = " .o+=*BOX@%&#/^SE";
>         char    *retval, *p, title[FLDSIZE_X], hash[FLDSIZE_X];
>         u_char   field[FLDSIZE_X][FLDSIZE_Y];
> @@ -1096,9 +1105,25 @@ fingerprint_randomart(const char *alg, u_char *dgst_raw, size_t dgst_raw_len,
>         int      x, y, r;
>         size_t   len = strlen(augmentation_string) - 1;
>
> -       if ((retval = calloc((FLDSIZE_X + 3), (FLDSIZE_Y + 2))) == NULL)
> +       if ((retval = malloc((FLDSIZE_X + 7) * FLDSIZE_Y + FLDSIZE_X * 3 * 2)) == NULL)
>                 return NULL;
>
> +#ifdef HAVE_LOCALE_H
> +       /* initialize locale */
> +       setlocale(LC_ALL, "");
> +
> +       /* get locale for LC_CTYPE and decide about characters to use */
> +       locale = setlocale(LC_CTYPE, NULL);
> +       if (locale != NULL && *locale != 0 &&
> +                       (strstr(locale, "UTF-8") ||
> +                        strstr(locale, "utf-8") ||
> +                        strstr(locale, "UTF8")  ||
> +                        strstr(locale, "utf8")))
> +               border = border_utf8;
> +       else
> +#endif
> +               border = border_ascii;
> +
>         /* initialize field */
>         memset(field, 0, FLDSIZE_X * FLDSIZE_Y * sizeof(char));
>         x = FLDSIZE_X / 2;
> @@ -1145,34 +1170,34 @@ fingerprint_randomart(const char *alg, u_char *dgst_raw, size_t dgst_raw_len,
>
>         /* output upper border */
>         p = retval;
> -       *p++ = '+';
> +       p += sprintf(p, "%s", border[0]);
>         for (i = 0; i < (FLDSIZE_X - tlen) / 2; i++)
> -               *p++ = '-';
> +               p += sprintf(p, "%s", border[1]);
>         memcpy(p, title, tlen);
>         p += tlen;
>         for (i += tlen; i < FLDSIZE_X; i++)
> -               *p++ = '-';
> -       *p++ = '+';
> +               p += sprintf(p, "%s", border[1]);
> +       p += sprintf(p, "%s", border[2]);
>         *p++ = '\n';
>
>         /* output content */
>         for (y = 0; y < FLDSIZE_Y; y++) {
> -               *p++ = '|';
> +               p += sprintf(p, "%s", border[3]);
>                 for (x = 0; x < FLDSIZE_X; x++)
>                         *p++ = augmentation_string[MIN(field[x][y], len)];
> -               *p++ = '|';
> +               p += sprintf(p, "%s", border[3]);
>                 *p++ = '\n';
>         }
>
>         /* output lower border */
> -       *p++ = '+';
> +       p += sprintf(p, "%s", border[4]);
>         for (i = 0; i < (FLDSIZE_X - hlen) / 2; i++)
> -               *p++ = '-';
> +               p += sprintf(p, "%s", border[1]);
>         memcpy(p, hash, hlen);
>         p += hlen;
>         for (i += hlen; i < FLDSIZE_X; i++)
> -               *p++ = '-';
> -       *p++ = '+';
> +               p += sprintf(p, "%s", border[1]);
> +       p += sprintf(p, "%s", border[5]);
>
>         return retval;
>  }

General comments:
1. Not all locales use UTF-8 as encoding but can still use the Unicode
characters you use (e.g. GB18030 is a modern example and it's use is
mandated by all software vendors in PRC China). A quick solution is to
use |iconv()| to convert the UTF-8 byte sequences to the local
encoding (see http://svn.nrubsig.org/svn/people/gisburn/code/ucs4towchar_t/ucs4towchar_t.c
- that could should be easy to modify). Note that if |iconf()|
produces an empty string in a character-by-character conversion it
means that the destination locale cannot represent that character in
the local encoding (you have to fall-back to the ASCII representation
then (this will also eliminate the need for the |setlocale()|&&co.
testing)).

2. UTF-8 sequences in ISO C code are not portable and a lot of
compilers will choke on that (e.g. if they are in a non-UTF-8 locale
like "C", "POSIX" or any non-UTF-8 multibyte locale). Correct fix
would be to provide the UTF-8 byte sequences for the characters as
plain C strings escaped in octal or hexadecimal notation (and then
squish them through |iconf()|)

3. Not all UTF-8 locales (or locale aliases) have "UTF-8" in their
name (for example the name "en_US" is allowed to be an alias for
"en_US.UTF-8" (this quickly becomes messy in the Chinese/Japanese
environments, e.g. where "ja_JP" can be anything from ja_JP.PCK to
ja_JP.UTF-8))

----

Bye,
Roland

-- 
  __ .  . __
 (o.\ \/ /.o) roland.mainz at nrubsig.org
  \__\/\/__/  MPEG specialist, C&&JAVA&&Sun&&Unix programmer
  /O /==\ O\  TEL +49 641 3992797
 (;O/ \/ \O;)


More information about the openssh-unix-dev mailing list