diff --git a/ChangeLog b/ChangeLog index 1cfbbfb8..b4ecb17e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,9 @@ What's new in version 0.7.1 +* Add Unicode support, enabled with the --enable-unicode + flag, which requires libncursesw. + (thanks to Sergej Pupykin) * BUGFIX: Fix display of CPU count for threaded processes. When user threads are hidden, process now shows the sum of processor usage for all processors. When user diff --git a/Makefile.am b/Makefile.am index 26b18aa7..5c148685 100644 --- a/Makefile.am +++ b/Makefile.am @@ -10,7 +10,7 @@ applications_DATA = htop.desktop pixmapdir = $(datadir)/pixmaps pixmap_DATA = htop.png -htop_CFLAGS = -pedantic -Wall -std=c99 +htop_CFLAGS = -pedantic -Wall -std=c99 -D_XOPEN_SOURCE_EXTENDED AM_CPPFLAGS = -DSYSCONFDIR=\"$(sysconfdir)\" myhtopsources = AvailableMetersPanel.c CategoriesPanel.c CheckItem.c \ diff --git a/Meter.c b/Meter.c index 0e9ef05f..fb7d8425 100644 --- a/Meter.c +++ b/Meter.c @@ -18,6 +18,7 @@ in the source distribution for its full text. #include "ListItem.h" #include "String.h" #include "ProcessList.h" +#include "RichString.h" #include "debug.h" #include @@ -266,7 +267,7 @@ void TextMeterMode_draw(Meter* this, int x, int y, int w) { Meter_displayToStringBuffer(this, buffer); mvhline(y, x, ' ', CRT_colors[DEFAULT_COLOR]); attrset(CRT_colors[RESET_COLOR]); - mvaddchstr(y, x, Meter_stringBuffer.chstr); + RichString_printVal(Meter_stringBuffer, y, x); } /* ---------- BarMeterMode ---------- */ @@ -418,7 +419,7 @@ void LEDMeterMode_draw(Meter* this, int x, int y, int w) { mvaddstr(y+2, x, this->caption); int xx = x + strlen(this->caption); for (int i = 0; i < Meter_stringBuffer.len; i++) { - char c = Meter_stringBuffer.chstr[i]; + char c = RichString_getCharVal(Meter_stringBuffer, i); if (c >= '0' && c <= '9') { LEDMeterMode_drawDigit(xx, y, c-48); xx += 4; diff --git a/Meter.h b/Meter.h index e564d3c3..8099a8ec 100644 --- a/Meter.h +++ b/Meter.h @@ -21,6 +21,7 @@ in the source distribution for its full text. #include "ListItem.h" #include "String.h" #include "ProcessList.h" +#include "RichString.h" #include "debug.h" #include diff --git a/Panel.c b/Panel.c index 14f542bc..00ff4c69 100644 --- a/Panel.c +++ b/Panel.c @@ -265,8 +265,8 @@ void Panel_draw(Panel* this, bool focus) { attrset(attr); mvhline(y, x, ' ', this->w); if (scrollH < this->header.len) { - mvaddchnstr(y, x, this->header.chstr + scrollH, - MIN(this->header.len - scrollH, this->w)); + RichString_printoffnVal(this->header, y, x, scrollH, + MIN(this->header.len - scrollH, this->w)); } attrset(CRT_colors[RESET_COLOR]); y++; @@ -289,12 +289,12 @@ void Panel_draw(Panel* this, bool focus) { RichString_setAttr(&itemRef, highlight); mvhline(y + j, x+0, ' ', this->w); if (amt > 0) - mvaddchnstr(y+j, x+0, itemRef.chstr + scrollH, amt); + RichString_printoffnVal(itemRef, y+j, x+0, scrollH, amt); attrset(CRT_colors[RESET_COLOR]); } else { mvhline(y+j, x+0, ' ', this->w); if (amt > 0) - mvaddchnstr(y+j, x+0, itemRef.chstr + scrollH, amt); + RichString_printoffnVal(itemRef, y+j, x+0, scrollH, amt); } } for (int i = y + (last - first); i < y + this->h; i++) @@ -312,12 +312,14 @@ void Panel_draw(Panel* this, bool focus) { newObj->display(newObj, &newRef); mvhline(y+ this->oldSelected - this->scrollV, x+0, ' ', this->w); if (scrollH < oldRef.len) - mvaddchnstr(y+ this->oldSelected - this->scrollV, x+0, oldRef.chstr + this->scrollH, MIN(oldRef.len - scrollH, this->w)); + RichString_printoffnVal(oldRef, y+this->oldSelected - this->scrollV, x, + this->scrollH, MIN(oldRef.len - scrollH, this->w)); attrset(highlight); mvhline(y+this->selected - this->scrollV, x+0, ' ', this->w); RichString_setAttr(&newRef, highlight); if (scrollH < newRef.len) - mvaddchnstr(y+this->selected - this->scrollV, x+0, newRef.chstr + this->scrollH, MIN(newRef.len - scrollH, this->w)); + RichString_printoffnVal(newRef, y+this->selected - this->scrollV, x, + this->scrollH, MIN(newRef.len - scrollH, this->w)); attrset(CRT_colors[RESET_COLOR]); } this->oldSelected = this->selected; diff --git a/Process.c b/Process.c index ab66d5bb..0b551ebb 100644 --- a/Process.c +++ b/Process.c @@ -11,6 +11,7 @@ in the source distribution for its full text. #include "CRT.h" #include "String.h" #include "Process.h" +#include "RichString.h" #include "debug.h" @@ -265,23 +266,20 @@ static void Process_printTime(RichString* str, unsigned long t) { } static inline void Process_writeCommand(Process* this, int attr, int baseattr, RichString* str) { + int start = str->len; + RichString_append(str, attr, this->comm); if (this->pl->highlightBaseName) { - char* firstSpace = strchr(this->comm, ' '); - if (firstSpace) { - char* slash = firstSpace; - while (slash > this->comm && *slash != '/') - slash--; - if (slash > this->comm) { - slash++; - RichString_appendn(str, attr, this->comm, slash - this->comm); - } - RichString_appendn(str, baseattr, slash, firstSpace - slash); - RichString_append(str, attr, firstSpace); - } else { - RichString_append(str, baseattr, this->comm); + int finish = str->len - 1; + int space = RichString_findChar(str, ' ', start); + if (space != -1) + finish = space - 1; + for (;;) { + int slash = RichString_findChar(str, '/', start); + if (slash == -1 || slash > finish) + break; + start = slash + 1; } - } else { - RichString_append(str, attr, this->comm); + RichString_setAttrn(str, baseattr, start, finish); } } diff --git a/Process.h b/Process.h index ac1c1af7..b107073d 100644 --- a/Process.h +++ b/Process.h @@ -14,6 +14,7 @@ in the source distribution for its full text. #include "Object.h" #include "CRT.h" #include "String.h" +#include "RichString.h" #include "debug.h" diff --git a/ProcessList.c b/ProcessList.c index 66d60949..04ac6f3e 100644 --- a/ProcessList.c +++ b/ProcessList.c @@ -283,7 +283,7 @@ void ProcessList_invertSortOrder(ProcessList* this) { RichString ProcessList_printHeader(ProcessList* this) { RichString out; - RichString_init(&out); + RichString_initVal(out); ProcessField* fields = this->fields; for (int i = 0; fields[i]; i++) { char* field = Process_printField(fields[i]); diff --git a/RichString.c b/RichString.c index 2cc7d172..c397f3f1 100644 --- a/RichString.c +++ b/RichString.c @@ -1,12 +1,20 @@ #include "RichString.h" +#ifndef CONFIG_H +#define CONFIG_H +#include "config.h" +#endif + #include #include #include #include "debug.h" #include +#ifdef HAVE_LIBNCURSESW +#include +#endif #define RICHSTRING_MAXLEN 300 @@ -15,9 +23,23 @@ #define RichString_init(this) (this)->len = 0 #define RichString_initVal(this) (this).len = 0 +#ifdef HAVE_LIBNCURSESW +#define RichString_printVal(this, y, x) mvadd_wchstr(y, x, this.chstr) +#define RichString_printoffnVal(this, y, x, off, n) mvadd_wchnstr(y, x, this.chstr + off, n) +#define RichString_getCharVal(this, i) (this.chstr[i].chars[0] & 255) +#else +#define RichString_printVal(this, y, x) mvaddchstr(y, x, this.chstr) +#define RichString_printoffnVal(this, y, x, off, n) mvaddchnstr(y, x, this.chstr + off, n) +#define RichString_getCharVal(this, i) (this.chstr[i]) +#endif + typedef struct RichString_ { int len; +#ifdef HAVE_LIBNCURSESW + cchar_t chstr[RICHSTRING_MAXLEN+1]; +#else chtype chstr[RICHSTRING_MAXLEN+1]; +#endif } RichString; }*/ @@ -26,14 +48,76 @@ typedef struct RichString_ { #define MIN(a,b) ((a)<(b)?(a):(b)) #endif -inline void RichString_appendn(RichString* this, int attrs, char* data, int len) { +#ifdef HAVE_LIBNCURSESW + +inline void RichString_appendn(RichString* this, int attrs, char* data_c, int len) { + wchar_t data[RICHSTRING_MAXLEN]; + len = mbstowcs(data, data_c, RICHSTRING_MAXLEN); + if (len<0) + return; + int last = MIN(RICHSTRING_MAXLEN - 1, len + this->len); + for (int i = this->len, j = 0; i < last; i++, j++) { + memset(&this->chstr[i], 0, sizeof(this->chstr[i])); + this->chstr[i].chars[0] = data[j]; + this->chstr[i].attr = attrs; + } + this->chstr[last].chars[0] = 0; + this->len = last; +} + +inline void RichString_setAttrn(RichString *this, int attrs, int start, int finish) { + cchar_t* ch = this->chstr + start; + for (int i = start; i <= finish; i++) { + ch->attr = attrs; + ch++; + } +} + +int RichString_findChar(RichString *this, char c, int start) { + wchar_t wc = btowc(c); + cchar_t* ch = this->chstr + start; + for (int i = start; i < this->len; i++) { + if (ch->chars[0] == wc) + return i; + ch++; + } + return -1; +} + +#else + +inline void RichString_appendn(RichString* this, int attrs, char* data_c, int len) { int last = MIN(RICHSTRING_MAXLEN - 1, len + this->len); for (int i = this->len, j = 0; i < last; i++, j++) - this->chstr[i] = data[j] | attrs; + this->chstr[i] = data_c[j] | attrs; this->chstr[last] = 0; this->len = last; } +void RichString_setAttrn(RichString *this, int attrs, int start, int finish) { + chtype* ch = this->chstr + start; + for (int i = start; i <= finish; i++) { + *ch = (*ch & 0xff) | attrs; + ch++; + } +} + +int RichString_findChar(RichString *this, char c, int start) { + chtype* ch = this->chstr + start; + for (int i = start; i < this->len; i++) { + if ((*ch & 0xff) == c) + return i; + ch++; + } + return -1; +} + +#endif + +void RichString_setAttr(RichString *this, int attrs) { + RichString_setAttrn(this, attrs, 0, this->len - 1); +} + inline void RichString_append(RichString* this, int attrs, char* data) { RichString_appendn(this, attrs, data, strlen(data)); } @@ -43,22 +127,6 @@ void RichString_write(RichString* this, int attrs, char* data) { RichString_append(this, attrs, data); } -void RichString_setAttr(RichString *this, int attrs) { - chtype* ch = this->chstr; - for (int i = 0; i < this->len; i++) { - *ch = (*ch & 0xff) | attrs; - ch++; - } -} - -void RichString_applyAttr(RichString *this, int attrs) { - chtype* ch = this->chstr; - for (int i = 0; i < this->len; i++) { - *ch |= attrs; - ch++; - } -} - RichString RichString_quickString(int attrs, char* data) { RichString str; RichString_initVal(str); diff --git a/RichString.h b/RichString.h index 6eed0d92..7f777bba 100644 --- a/RichString.h +++ b/RichString.h @@ -4,12 +4,20 @@ #define HEADER_RichString +#ifndef CONFIG_H +#define CONFIG_H +#include "config.h" +#endif + #include #include #include #include "debug.h" #include +#ifdef HAVE_LIBNCURSESW +#include +#endif #define RICHSTRING_MAXLEN 300 @@ -17,9 +25,23 @@ #define RichString_init(this) (this)->len = 0 #define RichString_initVal(this) (this).len = 0 +#ifdef HAVE_LIBNCURSESW +#define RichString_printVal(this, y, x) mvadd_wchstr(y, x, this.chstr) +#define RichString_printoffnVal(this, y, x, off, n) mvadd_wchnstr(y, x, this.chstr + off, n) +#define RichString_getCharVal(this, i) (this.chstr[i].chars[0] & 255) +#else +#define RichString_printVal(this, y, x) mvaddchstr(y, x, this.chstr) +#define RichString_printoffnVal(this, y, x, off, n) mvaddchnstr(y, x, this.chstr + off, n) +#define RichString_getCharVal(this, i) (this.chstr[i]) +#endif + typedef struct RichString_ { int len; +#ifdef HAVE_LIBNCURSESW + cchar_t chstr[RICHSTRING_MAXLEN+1]; +#else chtype chstr[RICHSTRING_MAXLEN+1]; +#endif } RichString; @@ -27,16 +49,30 @@ typedef struct RichString_ { #define MIN(a,b) ((a)<(b)?(a):(b)) #endif -extern void RichString_appendn(RichString* this, int attrs, char* data, int len); +#ifdef HAVE_LIBNCURSESW + +extern void RichString_appendn(RichString* this, int attrs, char* data_c, int len); + +extern void RichString_setAttrn(RichString *this, int attrs, int start, int finish); + +int RichString_findChar(RichString *this, char c, int start); + +#else + +extern void RichString_appendn(RichString* this, int attrs, char* data_c, int len); + +void RichString_setAttrn(RichString *this, int attrs, int start, int finish); + +int RichString_findChar(RichString *this, char c, int start); + +#endif + +void RichString_setAttr(RichString *this, int attrs); extern void RichString_append(RichString* this, int attrs, char* data); void RichString_write(RichString* this, int attrs, char* data); -void RichString_setAttr(RichString *this, int attrs); - -void RichString_applyAttr(RichString *this, int attrs); - RichString RichString_quickString(int attrs, char* data); #endif diff --git a/configure.ac b/configure.ac index f54310fc..f82eff9d 100644 --- a/configure.ac +++ b/configure.ac @@ -16,7 +16,6 @@ AM_ENABLE_STATIC AC_PROG_LIBTOOL # Checks for libraries. -AC_CHECK_LIB([ncurses], [refresh], [], [missing_libraries="$missing_libraries libncurses"]) AC_CHECK_LIB([m], [ceil], [], [missing_libraries="$missing_libraries libm"]) if test ! -z "$missing_libraries"; then @@ -67,7 +66,14 @@ AC_ARG_WITH(proc, [ --with-proc=DIR Location of a Linux-compatible proc fi AC_ARG_ENABLE(openvz, [AC_HELP_STRING([--enable-openvz], [enable OpenVZ support])], ,enable_openvz="no") if test "x$enable_openvz" = xyes; then - AC_DEFINE(HAVE_OPENVZ, 1, [Define if openvz support enabled.]) + AC_DEFINE(HAVE_OPENVZ, 1, [Define if openvz support enabled.]) +fi + +AC_ARG_ENABLE(unicode, [AC_HELP_STRING([--enable-unicode], [enable Unicode support])], ,enable_unicode="no") +if test "x$enable_unicode" = xyes; then + AC_CHECK_LIB([ncursesw], [refresh], [], [missing_libraries="$missing_libraries libncursesw"]) +else + AC_CHECK_LIB([ncurses], [refresh], [], [missing_libraries="$missing_libraries libncurses"]) fi AC_CHECK_FILE($PROCDIR/stat,,AC_MSG_ERROR(Cannot find /proc/stat. Make sure you have a Linux-compatible /proc filesystem mounted. See the file README for help.)) diff --git a/htop.c b/htop.c index ec5d79e3..50ecb416 100644 --- a/htop.c +++ b/htop.c @@ -11,6 +11,7 @@ in the source distribution for its full text. #include #include #include +#include #include "ProcessList.h" #include "CRT.h" @@ -221,6 +222,12 @@ int main(int argc, char** argv) { uid_t userId = 0; int sortKey = 0; + char *lc_ctype = getenv("LC_CTYPE"); + if(lc_ctype != NULL) + setlocale(LC_CTYPE, lc_ctype); + else + setlocale(LC_CTYPE, getenv("LC_ALL")); + int arg = 1; while (arg < argc) { if (String_eq(argv[arg], "--help")) { diff --git a/htop.h b/htop.h index 33745eb5..139019e0 100644 --- a/htop.h +++ b/htop.h @@ -15,6 +15,7 @@ in the source distribution for its full text. #include #include #include +#include #include "ProcessList.h" #include "CRT.h"