From 4417ed2dbf3c925b5c26d0a38234e0e30366b987 Mon Sep 17 00:00:00 2001 From: Daichi GOTO Date: Sun, 1 Jul 2018 05:32:03 +0000 Subject: [PATCH] top(1) - support UTF-8 display Reviewed by: eadler Approved by: gnn (mentor) Differential Revision: https://reviews.freebsd.org/D16006 --- usr.bin/top/display.c | 46 +++++++++++++++++++++++++-------- usr.bin/top/machine.c | 10 +++++--- usr.bin/top/top.c | 9 +++++++ usr.bin/top/top.h | 2 ++ usr.bin/top/utils.c | 59 +++++++++++++++++++++++++++++++++++++++++++ usr.bin/top/utils.h | 1 + 6 files changed, 113 insertions(+), 14 deletions(-) diff --git a/usr.bin/top/display.c b/usr.bin/top/display.c index d5673819d8e2..adc97a301f48 100644 --- a/usr.bin/top/display.c +++ b/usr.bin/top/display.c @@ -1258,19 +1258,43 @@ line_update(char *old, char *new, int start, int line) char * printable(char str[]) { - char *ptr; - char ch; + char *ptr; + char ch; - ptr = str; - while ((ch = *ptr) != '\0') - { - if (!isprint(ch)) - { - *ptr = '?'; + ptr = str; + if (utf8flag) { + while ((ch = *ptr) != '\0') { + if (0x00 == (0x80 & ch)) { + if (!isprint(ch)) { + *ptr = '?'; + } + ++ptr; + } else if (0xC0 == (0xE0 & ch)) { + ++ptr; + if ('\0' != *ptr) ++ptr; + } else if (0xE0 == (0xF0 & ch)) { + ++ptr; + if ('\0' != *ptr) ++ptr; + if ('\0' != *ptr) ++ptr; + } else if (0xF0 == (0xF8 & ch)) { + ++ptr; + if ('\0' != *ptr) ++ptr; + if ('\0' != *ptr) ++ptr; + if ('\0' != *ptr) ++ptr; + } else { + *ptr = '?'; + ++ptr; + } + } + } else { + while ((ch = *ptr) != '\0') { + if (!isprint(ch)) { + *ptr = '?'; + } + ptr++; + } } - ptr++; - } - return(str); + return(str); } void diff --git a/usr.bin/top/machine.c b/usr.bin/top/machine.c index c860213eabe0..fadcb81e1d33 100644 --- a/usr.bin/top/machine.c +++ b/usr.bin/top/machine.c @@ -988,9 +988,13 @@ format_next_process(struct handle * xhandle, char *(*get_userid)(int), int flags if (*src == '\0') continue; len = (argbuflen - (dst - argbuf) - 1) / 4; - strvisx(dst, src, - MIN(strlen(src), len), - VIS_NL | VIS_CSTYLE); + if (utf8flag) { + utf8strvisx(dst, src, MIN(strlen(src), len)); + } else { + strvisx(dst, src, + MIN(strlen(src), len), + VIS_NL | VIS_CSTYLE); + } while (*dst != '\0') dst++; if ((argbuflen - (dst - argbuf) - 1) / 4 > 0) diff --git a/usr.bin/top/top.c b/usr.bin/top/top.c index 558491da3c3b..e50651abf312 100644 --- a/usr.bin/top/top.c +++ b/usr.bin/top/top.c @@ -69,6 +69,7 @@ static int max_topn; /* maximum displayable processes */ struct process_select ps; const char * myname = "top"; pid_t mypid; +bool utf8flag = false; /* pointers to display routines */ static void (*d_loadave)(int mpid, double *avenrun) = i_loadave; @@ -606,6 +607,14 @@ main(int argc, char *argv[]) fputc('\n', stderr); } + /* check if you are using UTF-8 */ + char *env_lang; + if (NULL != (env_lang = getenv("LANG")) && + 0 != strcmp(env_lang, "") && + NULL != strstr(env_lang, "UTF-8")) { + utf8flag = true; + } + restart: /* diff --git a/usr.bin/top/top.h b/usr.bin/top/top.h index 0fe99d74e7f9..854970f8f925 100644 --- a/usr.bin/top/top.h +++ b/usr.bin/top/top.h @@ -8,6 +8,7 @@ #define TOP_H #include +#include /* Number of lines of header information on the standard screen */ extern int Header_lines; @@ -37,6 +38,7 @@ extern enum displaymodes displaymode; extern int pcpu_stats; extern int overstrike; extern pid_t mypid; +extern bool utf8flag; extern const char * myname; diff --git a/usr.bin/top/utils.c b/usr.bin/top/utils.c index 6ebc75e9b288..9149521a1e0b 100644 --- a/usr.bin/top/utils.c +++ b/usr.bin/top/utils.c @@ -2,6 +2,7 @@ * This program may be freely redistributed, * but this entire comment MUST remain intact. * + * Copyright (c) 2018, Daichi Goto * Copyright (c) 2018, Eitan Adler * Copyright (c) 1984, 1989, William LeFebvre, Rice University * Copyright (c) 1989, 1990, 1992, William LeFebvre, Northwestern University @@ -328,3 +329,61 @@ find_pid(pid_t pid) kvm_close(kd); return ret; } + +/* + * utf8strvisx(dst,src,src_len) + * strvisx(dst,src,src_len,VIS_NL|VIS_CSTYLE) coresponding to UTF-8. + */ +static const char *vis_encodes[] = { + "\\0", "\\^A", "\\^B", "\\^C", "\\^D", "\\^E", "\\^F", "\\a", + "\\b", "\t", "\\n", "\\v", "\\f", "\\r", "\\^N", "\\^O", "\\^P", + "\\^Q", "\\^R", "\\^S", "\\^T", "\\^U", "\\^V", "\\^W", "\\^X", + "\\^Y", "\\^Z", "\\^[", "\\^\\", "\\^]", "\\^^", "\\^_" +}; + +int +utf8strvisx(char *dst, const char *src, size_t src_len) +{ + const char *src_p; + char *dst_p; + int i, j, olen, len; + + src_p = src; + dst_p = dst; + i = olen = 0; + len = (int)src_len; + while (i < len) { + if (0x00 == (0x80 & *src_p)) { + if (0 <= *src_p && *src_p <= 31) { + j = strlen(vis_encodes[(int)*src_p]); + strcpy(dst_p, vis_encodes[(int)*src_p]); + dst_p += j; + olen += j; + } else if (127 == *src_p) { + strcpy(dst_p, "\\^?"); + olen += 3; + } else { + *dst_p++ = *src_p; + ++olen; + } + ++i; + ++src_p; + } else if (0xC0 == (0xE0 & *src_p)) { + *dst_p++ = *src_p++; ++i; ++olen; + if (i < len) { *dst_p++ = *src_p++; ++i; ++olen; } + } else if (0xE0 == (0xF0 & *src_p)) { + *dst_p++ = *src_p++; ++i; ++olen; + if (i < len) { *dst_p++ = *src_p++; ++i; ++olen; } + if (i < len) { *dst_p++ = *src_p++; ++i; ++olen; } + } else if (0xF0 == (0xF8 & *src_p)) { + *dst_p++ = *src_p++; ++i; ++olen; + if (i < len) { *dst_p++ = *src_p++; ++i; ++olen; } + if (i < len) { *dst_p++ = *src_p++; ++i; ++olen; } + if (i < len) { *dst_p++ = *src_p++; ++i; ++olen; } + } else { + *dst_p++ = '?'; ++i; ++olen; + } + } + + return olen; +} diff --git a/usr.bin/top/utils.h b/usr.bin/top/utils.h index 106e1da08963..6ced58505864 100644 --- a/usr.bin/top/utils.h +++ b/usr.bin/top/utils.h @@ -22,4 +22,5 @@ const char *format_time(long); char *format_k(int64_t); int string_index(const char *string, const char * const *array); int find_pid(pid_t pid); +int utf8strvisx(char *, const char *, size_t);