diff --git a/watch.c b/watch.c index a20ea4c9..c81711b2 100644 --- a/watch.c +++ b/watch.c @@ -1,11 +1,12 @@ -/* watch -- execute a program repeatedly, displaying output fullscreen +/* + * watch -- execute a program repeatedly, displaying output fullscreen * * Based on the original 1991 'watch' by Tony Rems * (with mods and corrections by Francois Pinard). * * Substantially reworked, new features (differences option, SIGWINCH - * handling, unlimited command length, long line handling) added Apr 1999 by - * Mike Coleman . + * handling, unlimited command length, long line handling) added Apr + * 1999 by Mike Coleman . * * Changes by Albert Cahalan, 2002-2003. * stderr handling, exec, and beep option added by Morty Abzug, 2008 @@ -13,137 +14,132 @@ */ #include "config.h" +#include "proc/procps.h" #include +#include +#include #include +#include +#include #include #include #include #include #include #include +#include +#include #include #include -#include -#include -#include "proc/procps.h" -#include #ifdef WITH_WATCH8BIT #include #include -#else +#else #include -#endif /* WITH_WATCH8BIT */ +#endif /* WITH_WATCH8BIT */ #ifdef FORCE_8BIT #undef isprint #define isprint(x) ( (x>=' '&&x<='~') || (x>=0xa0) ) #endif -static struct option longopts[] = { - {"color", no_argument, 0, 'c' }, - {"differences", optional_argument, 0, 'd'}, - {"help", no_argument, 0, 'h'}, - {"interval", required_argument, 0, 'n'}, - {"beep", no_argument, 0, 'b'}, - {"errexit", no_argument, 0, 'e'}, - {"exec", no_argument, 0, 'x'}, - {"precise", no_argument, 0, 'p'}, - {"no-title", no_argument, 0, 't'}, - {"version", no_argument, 0, 'v'}, - {0, 0, 0, 0} -}; - -static char usage[] = - "Usage: %s [-bdhnptvx] [--beep] [--color] [--differences[=cumulative]] [--exec] [--help] [--interval=] [--no-title] [--version] \n"; - -static char *progname; - static int curses_started = 0; static int height = 24, width = 80; static int screen_size_changed = 0; static int first_screen = 1; -static int show_title = 2; // number of lines used, 2 or 0 +static int show_title = 2; /* number of lines used, 2 or 0 */ static int precise_timekeeping = 0; #define min(x,y) ((x) > (y) ? (y) : (x)) #define MAX_ANSIBUF 10 +static void __attribute__ ((__noreturn__)) + usage(FILE * out) +{ + fprintf(out, + "\nUsage: %s [options] command\n" + "\nOptions:\n", program_invocation_short_name); + fprintf(out, + " -b, --beep beep if command has a non-zero exit\n" + " -c, --color interpret ANSI color sequences\n" + " -e, --errexit exit if command has a non-zero exit\n" + " -f, --differences highlight changes between updates\n" + " -n, --interval seconds to wait between updates\n" + " -p, --precise attempt run command in precise intervals\n" + " -t, --no-title turn off header\n" + " -x, --exec pass command to exec instead of \"sh -c\"\n" + " -h, --help display this help text\n" + " -v, --version display version information and exit\n"); + fprintf(out, "\nFor more information see watch(1).\n"); + + exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS); +} + static void init_ansi_colors(void) { - int i; - short ncurses_colors[] = { - COLOR_BLACK, COLOR_RED, COLOR_GREEN, COLOR_YELLOW, COLOR_BLUE, - COLOR_MAGENTA, COLOR_CYAN, COLOR_WHITE }; + int i; + short ncurses_colors[] = { + COLOR_BLACK, COLOR_RED, COLOR_GREEN, COLOR_YELLOW, COLOR_BLUE, + COLOR_MAGENTA, COLOR_CYAN, COLOR_WHITE + }; - for (i=0; i< 8; i++) - init_pair(i+1, ncurses_colors[i], -1); + for (i = 0; i < 8; i++) + init_pair(i + 1, ncurses_colors[i], -1); } static void set_ansi_attribute(const int attrib) { - switch (attrib) - { - case -1: - return; - case 0: - standend(); - return; - case 1: - attrset(A_BOLD); - return; - } - if (attrib >= 30 && attrib <= 37) { - color_set(attrib-29,NULL); - return; - } + switch (attrib) { + case -1: + return; + case 0: + standend(); + return; + case 1: + attrset(A_BOLD); + return; + } + if (attrib >= 30 && attrib <= 37) { + color_set(attrib - 29, NULL); + return; + } } -static void process_ansi(FILE *fp) +static void process_ansi(FILE * fp) { - int i,c, num1, num2; - char buf[MAX_ANSIBUF]; - char *nextnum; + int i, c, num1, num2; + char buf[MAX_ANSIBUF]; + char *nextnum; - - c= getc(fp); - if (c != '[') { - ungetc(c, fp); - return; - } - for(i=0; i '9' && c != ';') - { - while(--i >= 0) - ungetc(buf[i],fp); - return; - } - buf[i] = (char)c; - } - num1 = strtol(buf, &nextnum, 10); - if (nextnum != buf && nextnum[0] != '\0') - num2 = strtol(nextnum+1, NULL, 10); - else - num2 = -1; - set_ansi_attribute(num1); - set_ansi_attribute(num2); + c = getc(fp); + if (c != '[') { + ungetc(c, fp); + return; + } + for (i = 0; i < MAX_ANSIBUF; i++) { + c = getc(fp); + /* COLOUR SEQUENCE ENDS in 'm' */ + if (c == 'm') { + buf[i] = '\0'; + break; + } + if (c < '0' && c > '9' && c != ';') { + while (--i >= 0) + ungetc(buf[i], fp); + return; + } + buf[i] = (char)c; + } + num1 = strtol(buf, &nextnum, 10); + if (nextnum != buf && nextnum[0] != '\0') + num2 = strtol(nextnum + 1, NULL, 10); + else + num2 = -1; + set_ansi_attribute(num1); + set_ansi_attribute(num2); } -static void do_usage(void) NORETURN; -static void do_usage(void) -{ - fprintf(stderr, usage, progname); - exit(1); -} - -static void do_exit(int status) NORETURN; -static void do_exit(int status) +static void __attribute__ ((__noreturn__)) do_exit(int status) { if (curses_started) endwin(); @@ -151,17 +147,13 @@ static void do_exit(int status) } /* signal handler */ -static void die(int notused) NORETURN; -static void die(int notused) +static void die(int notused __attribute__ ((__unused__))) { - (void) notused; - do_exit(0); + do_exit(EXIT_SUCCESS); } -static void -winch_handler(int notused) +static void winch_handler(int notused __attribute__ ((__unused__))) { - (void) notused; screen_size_changed = 1; } @@ -170,46 +162,53 @@ static char env_row_buf[24]; static int incoming_cols; static int incoming_rows; -static void -get_terminal_size(void) +static void get_terminal_size(void) { struct winsize w; - if(!incoming_cols){ // have we checked COLUMNS? + if (!incoming_cols) { + /* have we checked COLUMNS? */ const char *s = getenv("COLUMNS"); incoming_cols = -1; - if(s && *s){ + if (s && *s) { long t; char *endptr; t = strtol(s, &endptr, 0); - if(!*endptr && (t>0) && (t<(long)666)) incoming_cols = (int)t; + if (!*endptr && (t > 0) && (t < (long)666)) + incoming_cols = (int)t; width = incoming_cols; - snprintf(env_col_buf, sizeof env_col_buf, "COLUMNS=%d", width); + snprintf(env_col_buf, sizeof env_col_buf, "COLUMNS=%d", + width); putenv(env_col_buf); } } - if(!incoming_rows){ // have we checked LINES? + if (!incoming_rows) { + /* have we checked LINES? */ const char *s = getenv("LINES"); incoming_rows = -1; - if(s && *s){ + if (s && *s) { long t; char *endptr; t = strtol(s, &endptr, 0); - if(!*endptr && (t>0) && (t<(long)666)) incoming_rows = (int)t; + if (!*endptr && (t > 0) && (t < (long)666)) + incoming_rows = (int)t; height = incoming_rows; - snprintf(env_row_buf, sizeof env_row_buf, "LINES=%d", height); + snprintf(env_row_buf, sizeof env_row_buf, "LINES=%d", + height); putenv(env_row_buf); } } - if (incoming_cols<0 || incoming_rows<0){ + if (incoming_cols < 0 || incoming_rows < 0) { if (ioctl(2, TIOCGWINSZ, &w) == 0) { - if (incoming_rows<0 && w.ws_row > 0){ + if (incoming_rows < 0 && w.ws_row > 0) { height = w.ws_row; - snprintf(env_row_buf, sizeof env_row_buf, "LINES=%d", height); + snprintf(env_row_buf, sizeof env_row_buf, + "LINES=%d", height); putenv(env_row_buf); } - if (incoming_cols<0 && w.ws_col > 0){ + if (incoming_cols < 0 && w.ws_col > 0) { width = w.ws_col; - snprintf(env_col_buf, sizeof env_col_buf, "COLUMNS=%d", width); + snprintf(env_col_buf, sizeof env_col_buf, + "COLUMNS=%d", width); putenv(env_col_buf); } } @@ -219,180 +218,186 @@ get_terminal_size(void) /* get current time in usec */ typedef unsigned long long watch_usec_t; #define USECS_PER_SEC (1000000ull) -watch_usec_t get_time_usec() { +watch_usec_t get_time_usec() +{ struct timeval now; gettimeofday(&now, NULL); - return USECS_PER_SEC*now.tv_sec + now.tv_usec; + return USECS_PER_SEC * now.tv_sec + now.tv_usec; } #ifdef WITH_WATCH8BIT -// read a wide character from a popen'd stream +/* 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 +wint_t my_getwc(FILE * s); +wint_t my_getwc(FILE * s) +{ + /* assuming no encoding ever consumes more than 16 bytes */ + char i[MAX_ENC_BYTES]; int byte = 0; int convert; int x; wchar_t rval; - while(1) { + while (1) { i[byte] = getc(s); - if (i[byte]==EOF) { return WEOF; } + 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; + if (convert > 0) { + /* legal conversion */ + return rval; + } + if (byte == MAX_ENC_BYTES) { + while (byte > 1) { + /* at least *try* to fix up */ + ungetc(i[--byte], s); + } + errno = -EILSEQ; + return WEOF; } } } -#endif /* WITH_WATCH8BIT */ +#endif /* WITH_WATCH8BIT */ -int -main(int argc, char *argv[]) +int main(int argc, char *argv[]) { int optc; int option_differences = 0, option_differences_cumulative = 0, - option_exec = 0, - option_beep = 0, - option_color = 0, - option_errexit = 0, - option_help = 0, option_version = 0; + option_exec = 0, + option_beep = 0, + option_color = 0, + option_errexit = 0, option_help = 0, option_version = 0; double interval = 2; char *command; char **command_argv; int command_length = 0; /* not including final \0 */ - watch_usec_t next_loop; /* next loop time in us, used for precise time - keeping only */ + watch_usec_t next_loop; /* next loop time in us, used for precise time + * keeping only */ #ifdef WITH_WATCH8BIT wchar_t *wcommand = NULL; int wcommand_columns = 0; /* not including final \0 */ - int wcommand_characters = 0; /* not including final \0 */ -#endif /* WITH_WATCH8BIT */ + int wcommand_characters = 0; /* not including final \0 */ +#endif /* WITH_WATCH8BIT */ int pipefd[2]; int status; pid_t child; - setlocale(LC_ALL, ""); - progname = argv[0]; + static struct option longopts[] = { + {"color", no_argument, 0, 'c'}, + {"differences", optional_argument, 0, 'd'}, + {"help", no_argument, 0, 'h'}, + {"interval", required_argument, 0, 'n'}, + {"beep", no_argument, 0, 'b'}, + {"errexit", no_argument, 0, 'e'}, + {"exec", no_argument, 0, 'x'}, + {"precise", no_argument, 0, 'p'}, + {"no-title", no_argument, 0, 't'}, + {"version", no_argument, 0, 'v'}, + {0, 0, 0, 0} + }; - while ((optc = getopt_long(argc, argv, "+bced::hn:pvtx", longopts, (int *) 0)) + setlocale(LC_ALL, ""); + + while ((optc = + getopt_long(argc, argv, "+bced::hn:pvtx", longopts, (int *)0)) != EOF) { switch (optc) { case 'b': option_beep = 1; break; - case 'c': - option_color = 1; - break; + case 'c': + option_color = 1; + break; case 'd': option_differences = 1; if (optarg) option_differences_cumulative = 1; break; - case 'e': - option_errexit = 1; - break; - case 'h': - option_help = 1; + case 'e': + option_errexit = 1; break; case 't': show_title = 0; break; case 'x': - option_exec = 1; + option_exec = 1; break; case 'n': { char *str; interval = strtod(optarg, &str); if (!*optarg || *str) - do_usage(); - if(interval < 0.1) + usage(stderr); + if (interval < 0.1) interval = 0.1; - if(interval > ~0u/1000000) - interval = ~0u/1000000; + if (interval > ~0u / 1000000) + interval = ~0u / 1000000; } break; case 'p': precise_timekeeping = 1; break; - case 'v': - option_version = 1; + case 'h': + usage(stdout); break; + case 'v': + display_version(); + return EXIT_SUCCESS; default: - do_usage(); + usage(stderr); break; } } - if (option_version) { - fprintf(stderr, "%s\n", PACKAGE_NAME " version " PACKAGE_VERSION); - if (!option_help) - exit(0); - } - - if (option_help) { - fprintf(stderr, usage, progname); - fputs(" -b, --beep\t\t\t\tbeep if the command has a non-zero exit\n", stderr); - fputs(" -d, --differences[=cumulative]\thighlight changes between updates\n", stderr); - fputs("\t\t(cumulative means highlighting is cumulative)\n", stderr); - fputs(" -e, --errexit\t\t\t\texit watch if the command has a non-zero exit\n", stderr); - fputs(" -h, --help\t\t\t\tprint a summary of the options\n", stderr); - fputs(" -n, --interval=\t\tseconds to wait between updates\n", stderr); - fputs(" -p, --precise\t\t\t\tprecise timing, ignore command run time\n", stderr); - fputs(" -v, --version\t\t\t\tprint the version number\n", stderr); - fputs(" -t, --no-title\t\t\tturns off showing the header\n", stderr); - fputs(" -x, --exec\t\t\t\tpass command to exec instead of sh\n", stderr); - exit(0); - } - if (optind >= argc) - do_usage(); + usage(stderr); - command_argv=&(argv[optind]); /* save for later */ + /* save for later */ + command_argv = &(argv[optind]); command = strdup(argv[optind++]); command_length = strlen(command); for (; optind < argc; optind++) { char *endp; int s = strlen(argv[optind]); - command = realloc(command, command_length + s + 2); /* space and \0 */ + /* space and \0 */ + command = realloc(command, command_length + s + 2); endp = command + command_length; *endp = ' '; memcpy(endp + 1, argv[optind], s); - command_length += 1 + s; /* space then string length */ + /* space then string length */ + command_length += 1 + s; command[command_length] = '\0'; } #ifdef WITH_WATCH8BIT - // convert to wide for printing purposes - //mbstowcs(NULL, NULL, 0); + /* convert to wide for printing purposes */ + /*mbstowcs(NULL, NULL, 0); */ wcommand_characters = mbstowcs(NULL, command, 0); - if(wcommand_characters < 0) { + if (wcommand_characters < 0) { fprintf(stderr, "Unicode Handling Error\n"); - exit(1); + exit(EXIT_FAILURE); } - wcommand = (wchar_t*)malloc((wcommand_characters+1) * sizeof(wcommand)); - if(wcommand == NULL) { + wcommand = + (wchar_t *) malloc((wcommand_characters + 1) * sizeof(wcommand)); + if (wcommand == NULL) { fprintf(stderr, "Unicode Handling Error (malloc)\n"); - exit(1); + exit(EXIT_FAILURE); } - mbstowcs(wcommand, command, wcommand_characters+1); + mbstowcs(wcommand, command, wcommand_characters + 1); wcommand_columns = wcswidth(wcommand, -1); -#endif /* WITH_WATCH8BIT */ - +#endif /* WITH_WATCH8BIT */ 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. */ signal(SIGINT, die); signal(SIGTERM, die); signal(SIGHUP, die); @@ -401,14 +406,14 @@ main(int argc, char *argv[]) /* Set up tty for curses use. */ curses_started = 1; initscr(); - if (option_color) { - if (has_colors()) { - start_color(); - use_default_colors(); - init_ansi_colors(); - } else - option_color = 0; - } + if (option_color) { + if (has_colors()) { + start_color(); + use_default_colors(); + init_ansi_colors(); + } else + option_color = 0; + } nonl(); noecho(); cbreak(); @@ -435,44 +440,70 @@ main(int argc, char *argv[]) } if (show_title) { - // left justify interval and command, - // right justify time, clipping all to fit window width - + /* + * left justify interval and command, right + * justify time, clipping all to fit window + * width + */ 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) { + /* + * 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 + 2) { + if (width < tsl + hlen + 4) { + mvaddstr(0, + width - tsl - + 4, "... "); + } else { #ifdef WITH_WATCH8BIT - if(width < tsl + hlen + wcommand_columns) { - // print truncated + 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) { + while (using_columns > avail_columns - 4) { using_characters--; - using_columns = wcswidth(wcommand, using_characters); + using_columns + = + wcswidth + (wcommand, + using_characters); } - mvaddnwstr(0, hlen, wcommand, using_characters); - mvaddstr(0, width - tsl - 4, "... "); - }else{ - mvaddwstr(0, hlen, wcommand); + mvaddnwstr(0, + hlen, + wcommand, + using_characters); + mvaddstr(0, + width - + tsl - + 4, + "... "); + } else { + mvaddwstr(0, + hlen, + wcommand); } #else - mvaddnstr(0, hlen, command, width - tsl - hlen); -#endif /* WITH_WATCH8BIT */ + mvaddnstr(0, hlen, + command, + width - tsl - + hlen); +#endif /* WITH_WATCH8BIT */ } } } @@ -483,101 +514,99 @@ main(int argc, char *argv[]) } /* allocate pipes */ - if (pipe(pipefd)<0) { - perror("pipe"); - do_exit(7); - } + if (pipe(pipefd) < 0) + err(7, "pipe"); /* flush stdout and stderr, since we're about to do fd stuff */ fflush(stdout); fflush(stderr); /* fork to prepare to run command */ - child=fork(); + child = fork(); - if (child<0) { /* fork error */ - perror("fork"); - do_exit(2); - } else if (child==0) { /* in child */ - close (pipefd[0]); /* child doesn't need read side of pipe */ - close (1); /* prepare to replace stdout with pipe */ - if (dup2 (pipefd[1], 1)<0) { /* replace stdout with write side of pipe */ - perror("dup2"); - exit(3); + if (child < 0) { /* fork error */ + err(2, "fork"); + } else if (child == 0) { /* in child */ + close(pipefd[0]); /* child doesn't need read side of pipe */ + close(1); /* prepare to replace stdout with pipe */ + if (dup2(pipefd[1], 1) < 0) { /* replace stdout with write side of pipe */ + err(3, "dup2"); } - dup2(1, 2); /* stderr should default to stdout */ + dup2(1, 2); /* stderr should default to stdout */ - if (option_exec) { /* pass command to exec instead of system */ - if (execvp(command_argv[0], command_argv)==-1) { - perror("exec"); - exit(4); + if (option_exec) { /* pass command to exec instead of system */ + if (execvp(command_argv[0], command_argv) == -1) { + err(4, "exec"); } } else { - status=system(command); /* watch manpage promises sh quoting */ + status = system(command); /* watch manpage promises sh quoting */ - /* propagate command exit status as child exit status */ - if (!WIFEXITED(status)) { /* child exits nonzero if command does */ - exit(1); - } else { - exit(WEXITSTATUS(status)); - } + /* propagate command exit status as child exit status */ + if (!WIFEXITED(status)) { /* child exits nonzero if command does */ + exit(EXIT_FAILURE); + } else { + exit(WEXITSTATUS(status)); + } } } /* otherwise, we're in parent */ - close(pipefd[1]); /* close write side of pipe */ - if ((p=fdopen(pipefd[0], "r"))==NULL) { - perror("fdopen"); - do_exit(5); - } - + close(pipefd[1]); /* close write side of pipe */ + if ((p = fdopen(pipefd[0], "r")) == NULL) + err(5, "fdopen"); for (y = show_title; y < height; y++) { int eolseen = 0, tabpending = 0; #ifdef WITH_WATCH8BIT wint_t carry = WEOF; -#endif /* WITH_WATCH8BIT */ +#endif /* WITH_WATCH8BIT */ for (x = 0; x < width; x++) { #ifdef WITH_WATCH8BIT wint_t c = ' '; #else int c = ' '; -#endif /* WITH_WATCH8BIT */ +#endif /* WITH_WATCH8BIT */ int attr = 0; if (!eolseen) { - /* if there is a tab pending, just spit spaces until the - next stop instead of reading characters */ - if (!tabpending) + /* if there is a tab pending, just + * spit spaces until the next stop + * instead of reading characters */ + if (!tabpending) #ifdef WITH_WATCH8BIT - do { - if(carry == WEOF) { - c = my_getwc(p); - }else{ - 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)); + do { + if (carry == WEOF) { + c = my_getwc(p); + } else { + 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)); #else do c = getc(p); while (c != EOF && !isprint(c) && c != '\n' && c != '\t' - && (c != L'\033' || option_color != 1)); -#endif /* WITH_WATCH8BIT */ - if (c == L'\033' && option_color == 1) { - x--; - process_ansi(p); - continue; - } - if (c == L'\n') - + && (c != L'\033' + || option_color != + 1)); +#endif /* WITH_WATCH8BIT */ + if (c == L'\033' && option_color == 1) { + x--; + process_ansi(p); + continue; + } + if (c == L'\n') if (!oldeolseen && x == 0) { x = -1; continue; @@ -586,31 +615,33 @@ main(int argc, char *argv[]) else if (c == L'\t') tabpending = 1; #ifdef WITH_WATCH8BIT - 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 (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' '; #else if (c == EOF || c == '\n' || c == '\t') c = ' '; -#endif /* WITH_WATCH8BIT */ +#endif /* WITH_WATCH8BIT */ if (tabpending && (((x + 1) % 8) == 0)) tabpending = 0; } move(y, x); if (option_differences) { #ifdef WITH_WATCH8BIT - cchar_t oldc; - in_wch(&oldc); + cchar_t oldc; + in_wch(&oldc); attr = !first_screen - && ((wchar_t)c != oldc.chars[0] + && ((wchar_t) c != oldc.chars[0] || (option_differences_cumulative - && (oldc.attr & A_ATTRIBUTES))); + && (oldc. + attr & A_ATTRIBUTES))); #else chtype oldch = inch(); unsigned char oldc = oldch & A_CHARTEXT; @@ -619,21 +650,25 @@ main(int argc, char *argv[]) || (option_differences_cumulative && (oldch & A_ATTRIBUTES))); -#endif /* WITH_WATCH8BIT */ +#endif /* WITH_WATCH8BIT */ } if (attr) standout(); #ifdef WITH_WATCH8BIT - addnwstr((wchar_t*)&c,1); + addnwstr((wchar_t *) & c, 1); #else addch(c); -#endif /* WITH_WATCH8BIT */ +#endif /* WITH_WATCH8BIT */ if (attr) standend(); #ifdef WITH_WATCH8BIT - if(wcwidth(c) == 0) { x--; } - if(wcwidth(c) == 2) { x++; } -#endif /* WITH_WATCH8BIT */ + if (wcwidth(c) == 0) { + x--; + } + if (wcwidth(c) == 2) { + x++; + } +#endif /* WITH_WATCH8BIT */ } oldeolseen = eolseen; } @@ -641,29 +676,29 @@ main(int argc, char *argv[]) fclose(p); /* harvest child process and get status, propagated from command */ - if (waitpid(child, &status, 0)<0) { - perror("waitpid"); - do_exit(8); - }; + if (waitpid(child, &status, 0) < 0) + err(8, "waitpid"); /* if child process exited in error, beep if option_beep is set */ if ((!WIFEXITED(status) || WEXITSTATUS(status))) { - if (option_beep) beep(); - if (option_errexit) do_exit(8); + if (option_beep) + beep(); + if (option_errexit) + exit(8); } first_screen = 0; refresh(); if (precise_timekeeping) { watch_usec_t cur_time = get_time_usec(); - next_loop += USECS_PER_SEC*interval; + next_loop += USECS_PER_SEC * interval; if (cur_time < next_loop) usleep(next_loop - cur_time); } else - usleep(interval * 1000000); + usleep(interval * 1000000); } endwin(); - return 0; + return EXIT_SUCCESS; }