Index: usr.bin/top/display.c =================================================================== --- usr.bin/top/display.c +++ usr.bin/top/display.c @@ -1258,19 +1258,48 @@ 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; + } + } } - ptr++; - } - return(str); + else { + while ((ch = *ptr) != '\0') { + if (!isprint(ch)) { + *ptr = '?'; + } + ptr++; + } + } + return(str); } void Index: usr.bin/top/machine.c =================================================================== --- usr.bin/top/machine.c +++ usr.bin/top/machine.c @@ -988,6 +988,9 @@ if (*src == '\0') continue; len = (argbuflen - (dst - argbuf) - 1) / 4; + if (utf8flag) + utf8strvisx(dst, src, MIN(strlen(src), len)); + else strvisx(dst, src, MIN(strlen(src), len), VIS_NL | VIS_CSTYLE); Index: usr.bin/top/top.h =================================================================== --- usr.bin/top/top.h +++ usr.bin/top/top.h @@ -37,6 +37,7 @@ extern int pcpu_stats; extern int overstrike; extern pid_t mypid; +extern int utf8flag; extern const char * myname; Index: usr.bin/top/top.c =================================================================== --- usr.bin/top/top.c +++ usr.bin/top/top.c @@ -69,6 +69,7 @@ struct process_select ps; const char * myname = "top"; pid_t mypid; +int utf8flag = 0; /* pointers to display routines */ static void (*d_loadave)(int mpid, double *avenrun) = i_loadave; @@ -606,6 +607,20 @@ fputc('\n', stderr); } + /* check if you are using UTF-8 */ + char *env_lang; + env_lang = getenv("LANG"); + int env_lang_len; + + if (NULL != env_lang) { + env_lang_len = strlen(env_lang); + if (5 <= env_lang_len) { + env_lang += env_lang_len - 5; + if (0 == strncmp(env_lang, "UTF-8", 5)) + utf8flag = 1; + } + } + restart: /* Index: usr.bin/top/utils.h =================================================================== --- usr.bin/top/utils.h +++ usr.bin/top/utils.h @@ -22,4 +22,5 @@ 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); Index: usr.bin/top/utils.c =================================================================== --- usr.bin/top/utils.c +++ 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,204 @@ kvm_close(kd); return ret; } + +/* + * utf8strvisx(dst,src,src_len) + * strvisx(dst,src,src_len,VIS_NL|VIS_CSTYLE) coresponding to UTF-8. + */ +int +utf8strvisx(char *dst, const char *src, size_t src_len) +{ + const char *src_p; + char *dst_p; + int i, olen, len; + + src_p = src; + dst_p = dst; + i = olen = 0; + len = (int)src_len; + while (i < len) { + if (0x00 == (0x80 & *src_p)) { + switch (*src_p) { + case 0: + *dst_p++ = '\\'; ++olen; + *dst_p++ = '0'; ++olen; + break; + case 1: + *dst_p++ = '\\'; ++olen; + *dst_p++ = '^'; ++olen; + *dst_p++ = 'A'; ++olen; + break; + case 2: + *dst_p++ = '\\'; ++olen; + *dst_p++ = '^'; ++olen; + *dst_p++ = 'B'; ++olen; + break; + case 3: + *dst_p++ = '\\'; ++olen; + *dst_p++ = '^'; ++olen; + *dst_p++ = 'C'; ++olen; + break; + case 4: + *dst_p++ = '\\'; ++olen; + *dst_p++ = '^'; ++olen; + *dst_p++ = 'D'; ++olen; + break; + case 5: + *dst_p++ = '\\'; ++olen; + *dst_p++ = '^'; ++olen; + *dst_p++ = 'E'; ++olen; + break; + case 6: + *dst_p++ = '\\'; ++olen; + *dst_p++ = '^'; ++olen; + *dst_p++ = 'F'; ++olen; + break; + case 7: + *dst_p++ = '\\'; ++olen; + *dst_p++ = 'a'; ++olen; + break; + case 8: + *dst_p++ = '\\'; ++olen; + *dst_p++ = 'b'; ++olen; + break; + case 10: + *dst_p++ = '\\'; ++olen; + *dst_p++ = 'n'; ++olen; + break; + case 11: + *dst_p++ = '\\'; ++olen; + *dst_p++ = 'v'; ++olen; + break; + case 12: + *dst_p++ = '\\'; ++olen; + *dst_p++ = 'f'; ++olen; + break; + case 13: + *dst_p++ = '\\'; ++olen; + *dst_p++ = 'r'; ++olen; + break; + case 14: + *dst_p++ = '\\'; ++olen; + *dst_p++ = '^'; ++olen; + *dst_p++ = 'N'; ++olen; + break; + case 15: + *dst_p++ = '\\'; ++olen; + *dst_p++ = '^'; ++olen; + *dst_p++ = 'O'; ++olen; + break; + case 16: + *dst_p++ = '\\'; ++olen; + *dst_p++ = '^'; ++olen; + *dst_p++ = 'P'; ++olen; + break; + case 17: + *dst_p++ = '\\'; ++olen; + *dst_p++ = '^'; ++olen; + *dst_p++ = 'Q'; ++olen; + break; + case 18: + *dst_p++ = '\\'; ++olen; + *dst_p++ = '^'; ++olen; + *dst_p++ = 'R'; ++olen; + break; + case 19: + *dst_p++ = '\\'; ++olen; + *dst_p++ = '^'; ++olen; + *dst_p++ = 'S'; ++olen; + break; + case 20: + *dst_p++ = '\\'; ++olen; + *dst_p++ = '^'; ++olen; + *dst_p++ = 'T'; ++olen; + break; + case 21: + *dst_p++ = '\\'; ++olen; + *dst_p++ = '^'; ++olen; + *dst_p++ = 'U'; ++olen; + break; + case 22: + *dst_p++ = '\\'; ++olen; + *dst_p++ = '^'; ++olen; + *dst_p++ = 'V'; ++olen; + break; + case 23: + *dst_p++ = '\\'; ++olen; + *dst_p++ = '^'; ++olen; + *dst_p++ = 'W'; ++olen; + break; + case 24: + *dst_p++ = '\\'; ++olen; + *dst_p++ = '^'; ++olen; + *dst_p++ = 'X'; ++olen; + break; + case 25: + *dst_p++ = '\\'; ++olen; + *dst_p++ = '^'; ++olen; + *dst_p++ = 'Y'; ++olen; + break; + case 26: + *dst_p++ = '\\'; ++olen; + *dst_p++ = '^'; ++olen; + *dst_p++ = 'Z'; ++olen; + break; + case 27: + *dst_p++ = '\\'; ++olen; + *dst_p++ = '^'; ++olen; + *dst_p++ = '['; ++olen; + break; + case 28: + *dst_p++ = '\\'; ++olen; + *dst_p++ = '^'; ++olen; + *dst_p++ = '\\'; ++olen; + break; + case 29: + *dst_p++ = '\\'; ++olen; + *dst_p++ = '^'; ++olen; + *dst_p++ = ']'; ++olen; + break; + case 30: + *dst_p++ = '\\'; ++olen; + *dst_p++ = '^'; ++olen; + *dst_p++ = '^'; ++olen; + break; + case 31: + *dst_p++ = '\\'; ++olen; + *dst_p++ = '^'; ++olen; + *dst_p++ = '_'; ++olen; + break; + case 127: + *dst_p++ = '\\'; ++olen; + *dst_p++ = '^'; ++olen; + *dst_p++ = '?'; ++olen; + break; + default: + *dst_p++ = *src_p; ++olen; + break; + } + ++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; +}