#! /bin/sh /usr/share/dpatch/dpatch-run ## 70_watch-unicode-3.2.8.dpatch by Jarrod Lowe ## ## All lines beginning with `## DP:' are a description of the patch. ## DP: Unicode support for watch @DPATCH@ diff -urNad procps-3.2.8~/AUTHORS procps-3.2.8/AUTHORS --- procps-3.2.8~/AUTHORS 2009-11-15 10:41:47.000000000 +0000 +++ procps-3.2.8/AUTHORS 2009-11-15 10:41:49.000000000 +0000 @@ -47,4 +47,5 @@ watch: Tony Rems Mike Coleman +Jarrod Lowe diff -urNad procps-3.2.8~/Makefile procps-3.2.8/Makefile --- procps-3.2.8~/Makefile 2009-11-15 10:41:49.000000000 +0000 +++ procps-3.2.8/Makefile 2009-11-15 10:41:49.000000000 +0000 @@ -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 will_this_file_really_exist.tmp $(CURSES) > /dev/null 2>&1; then echo "$(1)"; else echo "$(2)"; fi ; rm -f will_this_file_really_exist.tmp) +check_gcc = $(shell if $(CC) $(ALL_CPPFLAGS) $(ALL_CFLAGS) dummy.c $(ALL_LDFLAGS) $(1) -o will_this_file_really_exist.tmp $(CURSES) $(CURSESW) > /dev/null 2>&1; then echo "$(1)"; else echo "$(2)"; fi ; rm -f will_this_file_really_exist.tmp) # 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 diff -urNad procps-3.2.8~/watch.1 procps-3.2.8/watch.1 --- procps-3.2.8~/watch.1 2009-11-15 10:41:49.000000000 +0000 +++ procps-3.2.8/watch.1 2009-11-15 10:44:12.000000000 +0000 @@ -136,8 +136,19 @@ .B \-\-differences highlighting is lost on that update as well. .PP -Non-printing characters are stripped from program output. Use "cat -v" as -part of the command pipeline if you want to see them. +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 +Invalid byte sequences (i.e. ones that are illegal in the current encoding) +are treated as end-of-file. +.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 @@ -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. +In 2009, Jarrod Lowe added Unicode support. diff -urNad procps-3.2.8~/watch.c procps-3.2.8/watch.c --- procps-3.2.8~/watch.c 2009-11-15 10:41:49.000000000 +0000 +++ procps-3.2.8/watch.c 2009-11-15 10:41:49.000000000 +0000 @@ -11,12 +11,13 @@ * stderr handling, exec, and beep option added by Morty Abzug, 2008 */ -#define VERSION "0.2.0" +#define VERSION "0.3.0" +#include #include #include #include -#include +#include #include #include #include @@ -28,11 +29,6 @@ #include #include "proc/procps.h" -#ifdef FORCE_8BIT -#undef isprint -#define isprint(x) ( (x>=' '&&x<='~') || (x>=0xa0) ) -#endif - static struct option longopts[] = { {"differences", optional_argument, 0, 'd'}, {"help", no_argument, 0, 'h'}, @@ -162,8 +158,12 @@ 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 +259,21 @@ command[command_length] = '\0'; } + //convert command to wide for printing purposes + 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,13 +313,45 @@ 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); - free(header); + 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); + + } /* allocate pipes */ @@ -360,47 +407,64 @@ 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 = getwc(p); + }else{ + c = carry; + carry = WEOF; + } + }while (c != WEOF + //isprint segfault on multibyte + && (c<128 && !isprint(c)) + && 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; }