watch: support unicode
A patch from Debian. Bug-Debian: http://bugs.debian.org/240989 Bug-Ubuntu: https://bugs.launchpad.net/ubuntu/+source/procps/+bug/318221 Backported-by: Sami Kerola <kerolasa@iki.fi>
This commit is contained in:
parent
0dbdb862b1
commit
8967f0fca3
1
AUTHORS
1
AUTHORS
@ -47,4 +47,5 @@ Charles Blake
|
|||||||
watch:
|
watch:
|
||||||
Tony Rems <rembo@unisoft.com>
|
Tony Rems <rembo@unisoft.com>
|
||||||
Mike Coleman <mkc@acm.org>
|
Mike Coleman <mkc@acm.org>
|
||||||
|
Jarrod Lowe <procps@rrod.net>
|
||||||
|
|
||||||
|
12
watch.1
12
watch.1
@ -144,6 +144,17 @@ highlighting is lost on that update as well.
|
|||||||
Non-printing characters are stripped from program output. Use "cat -v" as
|
Non-printing characters are stripped from program output. Use "cat -v" as
|
||||||
part of the command pipeline if you want to see them.
|
part of the command pipeline if you want to see them.
|
||||||
.PP
|
.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
|
.I \-\-precise
|
||||||
mode doesn't yet have advanced temporal distortion technology to
|
mode doesn't yet have advanced temporal distortion technology to
|
||||||
compensate for a
|
compensate for a
|
||||||
@ -170,3 +181,4 @@ On a not so dark and stormy morning
|
|||||||
in March of 2003, Anthony DeRobertis <asd@suespammers.org> got sick of
|
in March of 2003, Anthony DeRobertis <asd@suespammers.org> got sick of
|
||||||
his watches that should update every minute eventually updating many
|
his watches that should update every minute eventually updating many
|
||||||
seconds after the minute started, and added microsecond precision.
|
seconds after the minute started, and added microsecond precision.
|
||||||
|
Unicode support was added in 2009 by Jarrod Lowe <procps@rrod.net>.
|
||||||
|
132
watch.c
132
watch.c
@ -9,6 +9,7 @@
|
|||||||
*
|
*
|
||||||
* Changes by Albert Cahalan, 2002-2003.
|
* Changes by Albert Cahalan, 2002-2003.
|
||||||
* stderr handling, exec, and beep option added by Morty Abzug, 2008
|
* stderr handling, exec, and beep option added by Morty Abzug, 2008
|
||||||
|
* Unicode Support added by Jarrod Lowe <procps@rrod.net> in 2009.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
@ -26,6 +27,7 @@
|
|||||||
#include <locale.h>
|
#include <locale.h>
|
||||||
#include "proc/procps.h"
|
#include "proc/procps.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
#ifdef FORCE_8BIT
|
#ifdef FORCE_8BIT
|
||||||
#undef isprint
|
#undef isprint
|
||||||
@ -218,6 +220,32 @@ watch_usec_t get_time_usec() {
|
|||||||
return USECS_PER_SEC*now.tv_sec + now.tv_usec;
|
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
|
int
|
||||||
main(int argc, char *argv[])
|
main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
@ -231,8 +259,11 @@ main(int argc, char *argv[])
|
|||||||
option_help = 0, option_version = 0;
|
option_help = 0, option_version = 0;
|
||||||
double interval = 2;
|
double interval = 2;
|
||||||
char *command;
|
char *command;
|
||||||
|
wchar_t *wcommand = NULL;
|
||||||
char **command_argv;
|
char **command_argv;
|
||||||
int command_length = 0; /* not including final \0 */
|
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
|
watch_usec_t next_loop; /* next loop time in us, used for precise time
|
||||||
keeping only */
|
keeping only */
|
||||||
int pipefd[2];
|
int pipefd[2];
|
||||||
@ -331,6 +362,23 @@ main(int argc, char *argv[])
|
|||||||
command[command_length] = '\0';
|
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();
|
get_terminal_size();
|
||||||
|
|
||||||
/* Catch keyboard interrupts so we can put tty back in a sane state. */
|
/* Catch keyboard interrupts so we can put tty back in a sane state. */
|
||||||
@ -378,12 +426,44 @@ main(int argc, char *argv[])
|
|||||||
if (show_title) {
|
if (show_title) {
|
||||||
// left justify interval and command,
|
// left justify interval and command,
|
||||||
// right justify time, clipping all to fit window width
|
// right justify time, clipping all to fit window width
|
||||||
asprintf(&header, "Every %.1fs: %.*s",
|
|
||||||
interval, min(width - 1, command_length), command);
|
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);
|
mvaddstr(0, 0, header);
|
||||||
if (strlen(header) > (size_t) (width - tsl - 1))
|
if(width >= tsl + hlen + 2) {
|
||||||
|
if(width < tsl + hlen + 4) {
|
||||||
mvaddstr(0, width - tsl - 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);
|
mvaddstr(0, width - tsl + 1, ts);
|
||||||
|
}
|
||||||
|
|
||||||
free(header);
|
free(header);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -440,53 +520,69 @@ main(int argc, char *argv[])
|
|||||||
|
|
||||||
for (y = show_title; y < height; y++) {
|
for (y = show_title; y < height; y++) {
|
||||||
int eolseen = 0, tabpending = 0;
|
int eolseen = 0, tabpending = 0;
|
||||||
|
wint_t carry = WEOF;
|
||||||
for (x = 0; x < width; x++) {
|
for (x = 0; x < width; x++) {
|
||||||
int c = ' ';
|
wint_t c = ' ';
|
||||||
int attr = 0;
|
int attr = 0;
|
||||||
|
|
||||||
if (!eolseen) {
|
if (!eolseen) {
|
||||||
/* if there is a tab pending, just spit spaces until the
|
/* if there is a tab pending, just spit spaces until the
|
||||||
next stop instead of reading characters */
|
next stop instead of reading characters */
|
||||||
if (!tabpending)
|
if (!tabpending)
|
||||||
do
|
do {
|
||||||
c = getc(p);
|
if(carry == WEOF) {
|
||||||
while (c != EOF && !isprint(c)
|
c = my_getwc(p);
|
||||||
&& c != '\n'
|
}else{
|
||||||
&& c != '\t'
|
c = carry;
|
||||||
|
carry = WEOF;
|
||||||
|
}
|
||||||
|
}while (c != WEOF && !isprint(c) && c<12
|
||||||
|
&& wcwidth(c) == 0
|
||||||
|
&& c != L'\n'
|
||||||
|
&& c != L'\t'
|
||||||
&& (c != L'\033' || option_color != 1));
|
&& (c != L'\033' || option_color != 1));
|
||||||
if (c == L'\033' && option_color == 1) {
|
if (c == L'\033' && option_color == 1) {
|
||||||
x--;
|
x--;
|
||||||
process_ansi(p);
|
process_ansi(p);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (c == '\n')
|
if (c == L'\n')
|
||||||
|
|
||||||
if (!oldeolseen && x == 0) {
|
if (!oldeolseen && x == 0) {
|
||||||
x = -1;
|
x = -1;
|
||||||
continue;
|
continue;
|
||||||
} else
|
} else
|
||||||
eolseen = 1;
|
eolseen = 1;
|
||||||
else if (c == '\t')
|
else if (c == L'\t')
|
||||||
tabpending = 1;
|
tabpending = 1;
|
||||||
if (c == EOF || c == '\n' || c == '\t')
|
if (x==width-1 && wcwidth(c)==2) {
|
||||||
c = ' ';
|
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))
|
if (tabpending && (((x + 1) % 8) == 0))
|
||||||
tabpending = 0;
|
tabpending = 0;
|
||||||
}
|
}
|
||||||
move(y, x);
|
move(y, x);
|
||||||
if (option_differences) {
|
if (option_differences) {
|
||||||
chtype oldch = inch();
|
cchar_t oldc;
|
||||||
unsigned char oldc = oldch & A_CHARTEXT;
|
in_wch(&oldc);
|
||||||
attr = !first_screen
|
attr = !first_screen
|
||||||
&& ((unsigned char)c != oldc
|
&& ((wchar_t)c != oldc.chars[0]
|
||||||
||
|
||
|
||||||
(option_differences_cumulative
|
(option_differences_cumulative
|
||||||
&& (oldch & A_ATTRIBUTES)));
|
&& (oldc.attr & A_ATTRIBUTES)));
|
||||||
}
|
}
|
||||||
if (attr)
|
if (attr)
|
||||||
standout();
|
standout();
|
||||||
addch(c);
|
addnwstr((wchar_t*)&c,1);
|
||||||
if (attr)
|
if (attr)
|
||||||
standend();
|
standend();
|
||||||
|
if(wcwidth(c) == 0) { x--; }
|
||||||
|
if(wcwidth(c) == 2) { x++; }
|
||||||
}
|
}
|
||||||
oldeolseen = eolseen;
|
oldeolseen = eolseen;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user