Description: Unicode/8bit for watch Bug-Debian: http://bugs.debian.org/240989 Bug-Ubuntu: https://bugs.launchpad.net/ubuntu/+source/procps/+bug/318221 Author: Jarrod Lowe --- a/AUTHORS +++ b/AUTHORS @@ -47,4 +47,5 @@ watch: Tony Rems Mike Coleman +Jarrod Lowe --- a/Makefile +++ b/Makefile @@ -68,6 +68,7 @@ _TARFILES := Makefile CURSES := -lncurses +CURSESW := -lncursesw # This seems about right for the dynamic library stuff. # Something like this is probably needed to make the SE Linux @@ -119,7 +120,7 @@ # Unlike the kernel one, this check_gcc goes all the way to # producing an executable. There might be a -m64 that works # until you go looking for a 64-bit curses library. -check_gcc = $(shell if $(CC) $(ALL_CPPFLAGS) $(ALL_CFLAGS) dummy.c $(ALL_LDFLAGS) $(1) -o /dev/null $(CURSES) > /dev/null 2>&1; then echo "$(1)"; else echo "$(2)"; fi ;) +check_gcc = $(shell if $(CC) $(ALL_CPPFLAGS) $(ALL_CFLAGS) dummy.c $(ALL_LDFLAGS) $(1) -o /dev/null $(CURSES) $(CURSESW) > /dev/null 2>&1; then echo "$(1)"; else echo "$(2)"; fi ;) # Be 64-bit if at all possible. In a cross-compiling situation, one may # do "make m64=-m32 lib64=lib" to produce 32-bit executables. DO NOT @@ -250,7 +251,7 @@ $(CC) $(ALL_CFLAGS) $^ $(ALL_LDFLAGS) -o $@ $(CURSES) watch: % : %.o - $(CC) $(ALL_CFLAGS) $^ $(ALL_LDFLAGS) -o $@ $(CURSES) + $(CC) $(ALL_CFLAGS) $^ $(ALL_LDFLAGS) -o $@ $(CURSESW) ############ progX --> progY --- a/watch.1 +++ b/watch.1 @@ -139,6 +139,17 @@ Non-printing characters are stripped from program output. Use "cat -v" as part of the command pipeline if you want to see them. .PP +Combining Characters that are supposed to display on the character at the +last column on the screen may display one column early, or they may not +display at all. +.PP +Combining Characters never count as different in +.I \-\-differences +mode. Only the base character counts. +.PP +Blank lines directly after a line which ends in the last column do not +display. +.PP .I \-\-precise mode doesn't yet have advanced temporal distortion technology to compensate for a @@ -165,3 +176,4 @@ in March of 2003, Anthony DeRobertis got sick of his watches that should update every minute eventually updating many seconds after the minute started, and added microsecond precision. +Unicode support was added in 2009 by Jarrod Lowe . --- a/watch.c +++ b/watch.c @@ -9,14 +9,16 @@ * * Changes by Albert Cahalan, 2002-2003. * stderr handling, exec, and beep option added by Morty Abzug, 2008 + * Unicode Support added by Jarrod Lowe in 2009. */ -#define VERSION "0.2.0" +#define VERSION "0.3.0" +#include #include #include #include -#include +#include #include #include #include @@ -27,6 +29,7 @@ #include #include #include "proc/procps.h" +#include #ifdef FORCE_8BIT #undef isprint @@ -150,6 +153,32 @@ return USECS_PER_SEC*now.tv_sec + now.tv_usec; } +// read a wide character from a popen'd stream +#define MAX_ENC_BYTES 16 +wint_t my_getwc(FILE *s); +wint_t my_getwc(FILE *s) { + char i[MAX_ENC_BYTES]; //assuming no encoding ever consumes more than 16 bytes + int byte = 0; + int convert; + int x; + wchar_t rval; + while(1) { + i[byte] = getc(s); + if (i[byte]==EOF) { return WEOF; } + byte++; + errno = 0; + mbtowc(NULL, NULL, 0); + convert = mbtowc(&rval, i, byte); + x = errno; + if(convert > 0) { return rval; } //legal conversion + if(byte == MAX_ENC_BYTES) { + while(byte > 1) { ungetc(i[--byte], s); } //at least *try* to fix up + errno = -EILSEQ; + return WEOF; + } + } +} + int main(int argc, char *argv[]) { @@ -162,8 +191,11 @@ option_help = 0, option_version = 0; double interval = 2; char *command; + wchar_t *wcommand = NULL; char **command_argv; int command_length = 0; /* not including final \0 */ + int wcommand_columns = 0; /* not including final \0 */ + int wcommand_characters = 0; /* not including final \0 */ watch_usec_t next_loop; /* next loop time in us, used for precise time keeping only */ int pipefd[2]; @@ -259,6 +291,23 @@ command[command_length] = '\0'; } + // convert to wide for printing purposes + //mbstowcs(NULL, NULL, 0); + wcommand_characters = mbstowcs(NULL, command, 0); + if(wcommand_characters < 0) { + fprintf(stderr, "Unicode Handling Error\n"); + exit(1); + } + wcommand = (wchar_t*)malloc((wcommand_characters+1) * sizeof(wcommand)); + if(wcommand == NULL) { + fprintf(stderr, "Unicode Handling Error (malloc)\n"); + exit(1); + } + mbstowcs(wcommand, command, wcommand_characters+1); + wcommand_columns = wcswidth(wcommand, -1); + + + get_terminal_size(); /* Catch keyboard interrupts so we can put tty back in a sane state. */ @@ -298,12 +347,44 @@ if (show_title) { // left justify interval and command, // right justify time, clipping all to fit window width - asprintf(&header, "Every %.1fs: %.*s", - interval, min(width - 1, command_length), command); - mvaddstr(0, 0, header); - if (strlen(header) > (size_t) (width - tsl - 1)) - mvaddstr(0, width - tsl - 4, "... "); - mvaddstr(0, width - tsl + 1, ts); + + int hlen = asprintf(&header, "Every %.1fs: ", interval); + + // the rules: + // width < tsl : print nothing + // width < tsl + hlen + 1: print ts + // width = tsl + hlen + 1: print header, ts + // width < tsl + hlen + 4: print header, ..., ts + // width < tsl + hlen + wcommand_columns: print header, truncated wcommand, ..., ts + // width > "": print header, wcomand, ts + // this is slightly different from how it used to be + if(width >= tsl) { + if(width >= tsl + hlen + 1) { + mvaddstr(0, 0, header); + if(width >= tsl + hlen + 2) { + if(width < tsl + hlen + 4) { + mvaddstr(0, width - tsl - 4, "... "); + }else{ + if(width < tsl + hlen + wcommand_columns) { + // print truncated + int avail_columns = width - tsl - hlen; + int using_columns = wcommand_columns; + int using_characters = wcommand_characters; + while(using_columns > avail_columns - 4) { + using_characters--; + using_columns = wcswidth(wcommand, using_characters); + } + mvaddnwstr(0, hlen, wcommand, using_characters); + mvaddstr(0, width - tsl - 4, "... "); + }else{ + mvaddwstr(0, hlen, wcommand); + } + } + } + } + mvaddstr(0, width - tsl + 1, ts); + } + free(header); } @@ -360,47 +441,62 @@ for (y = show_title; y < height; y++) { int eolseen = 0, tabpending = 0; + wint_t carry = WEOF; for (x = 0; x < width; x++) { - int c = ' '; + wint_t c = L' '; int attr = 0; if (!eolseen) { /* if there is a tab pending, just spit spaces until the next stop instead of reading characters */ if (!tabpending) - do - c = getc(p); - while (c != EOF && !isprint(c) - && c != '\n' - && c != '\t'); - if (c == '\n') + do { + if(carry == WEOF) { + c = my_getwc(p); + }else{ + c = carry; + carry = WEOF; + } + }while (c != WEOF && !isprint(c) && c<128 + && wcwidth(c) == 0 + && c != L'\n' + && c != L'\t'); + if (c == L'\n') if (!oldeolseen && x == 0) { x = -1; continue; } else eolseen = 1; - else if (c == '\t') + else if (c == L'\t') tabpending = 1; - if (c == EOF || c == '\n' || c == '\t') - c = ' '; + if (x==width-1 && wcwidth(c)==2) { + y++; + x = -1; //process this double-width + carry = c; //character on the next line + continue; //because it won't fit here + } + if (c == WEOF || c == L'\n' || c == L'\t') + c = L' '; if (tabpending && (((x + 1) % 8) == 0)) tabpending = 0; } move(y, x); if (option_differences) { - chtype oldch = inch(); - unsigned char oldc = oldch & A_CHARTEXT; + cchar_t oldc; + in_wch(&oldc); attr = !first_screen - && ((char)c != oldc + && ((wchar_t)c != oldc.chars[0] || (option_differences_cumulative - && (oldch & A_ATTRIBUTES))); + && (oldc.attr & A_ATTRIBUTES))); } if (attr) standout(); - addch(c); + addnwstr((wchar_t*)&c,1); if (attr) standend(); + if(wcwidth(c) == 0) { x--; } + if(wcwidth(c) == 2) { x++; } } oldeolseen = eolseen; }