watch: new usage & fix coding style

Coding style fixed and more readable help output.

Signed-off-by: Sami Kerola <kerolasa@iki.fi>
This commit is contained in:
Sami Kerola 2011-06-05 15:05:47 +02:00
parent 2865ded64e
commit 6dd092412f

663
watch.c
View File

@ -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 <rembo@unisoft.com> * Based on the original 1991 'watch' by Tony Rems <rembo@unisoft.com>
* (with mods and corrections by Francois Pinard). * (with mods and corrections by Francois Pinard).
* *
* Substantially reworked, new features (differences option, SIGWINCH * Substantially reworked, new features (differences option, SIGWINCH
* handling, unlimited command length, long line handling) added Apr 1999 by * handling, unlimited command length, long line handling) added Apr
* Mike Coleman <mkc@acm.org>. * 1999 by Mike Coleman <mkc@acm.org>.
* *
* 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
@ -13,137 +14,132 @@
*/ */
#include "config.h" #include "config.h"
#include "proc/procps.h"
#include <ctype.h> #include <ctype.h>
#include <errno.h>
#include <errno.h>
#include <getopt.h> #include <getopt.h>
#include <locale.h>
#include <locale.h>
#include <signal.h> #include <signal.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <sys/time.h> #include <sys/time.h>
#include <termios.h>
#include <termios.h>
#include <time.h> #include <time.h>
#include <unistd.h> #include <unistd.h>
#include <termios.h>
#include <locale.h>
#include "proc/procps.h"
#include <errno.h>
#ifdef WITH_WATCH8BIT #ifdef WITH_WATCH8BIT
#include <wchar.h> #include <wchar.h>
#include <ncursesw/ncurses.h> #include <ncursesw/ncurses.h>
#else #else
#include <ncurses.h> #include <ncurses.h>
#endif /* WITH_WATCH8BIT */ #endif /* WITH_WATCH8BIT */
#ifdef FORCE_8BIT #ifdef FORCE_8BIT
#undef isprint #undef isprint
#define isprint(x) ( (x>=' '&&x<='~') || (x>=0xa0) ) #define isprint(x) ( (x>=' '&&x<='~') || (x>=0xa0) )
#endif #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=<n>] [--no-title] [--version] <command>\n";
static char *progname;
static int curses_started = 0; static int curses_started = 0;
static int height = 24, width = 80; static int height = 24, width = 80;
static int screen_size_changed = 0; static int screen_size_changed = 0;
static int first_screen = 1; 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; static int precise_timekeeping = 0;
#define min(x,y) ((x) > (y) ? (y) : (x)) #define min(x,y) ((x) > (y) ? (y) : (x))
#define MAX_ANSIBUF 10 #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 <secs> 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) static void init_ansi_colors(void)
{ {
int i; int i;
short ncurses_colors[] = { short ncurses_colors[] = {
COLOR_BLACK, COLOR_RED, COLOR_GREEN, COLOR_YELLOW, COLOR_BLUE, COLOR_BLACK, COLOR_RED, COLOR_GREEN, COLOR_YELLOW, COLOR_BLUE,
COLOR_MAGENTA, COLOR_CYAN, COLOR_WHITE }; COLOR_MAGENTA, COLOR_CYAN, COLOR_WHITE
};
for (i=0; i< 8; i++) for (i = 0; i < 8; i++)
init_pair(i+1, ncurses_colors[i], -1); init_pair(i + 1, ncurses_colors[i], -1);
} }
static void set_ansi_attribute(const int attrib) static void set_ansi_attribute(const int attrib)
{ {
switch (attrib) switch (attrib) {
{ case -1:
case -1: return;
return; case 0:
case 0: standend();
standend(); return;
return; case 1:
case 1: attrset(A_BOLD);
attrset(A_BOLD); return;
return; }
} if (attrib >= 30 && attrib <= 37) {
if (attrib >= 30 && attrib <= 37) { color_set(attrib - 29, NULL);
color_set(attrib-29,NULL); return;
return; }
}
} }
static void process_ansi(FILE *fp) static void process_ansi(FILE * fp)
{ {
int i,c, num1, num2; int i, c, num1, num2;
char buf[MAX_ANSIBUF]; char buf[MAX_ANSIBUF];
char *nextnum; char *nextnum;
c = getc(fp);
c= getc(fp); if (c != '[') {
if (c != '[') { ungetc(c, fp);
ungetc(c, fp); return;
return; }
} for (i = 0; i < MAX_ANSIBUF; i++) {
for(i=0; i<MAX_ANSIBUF; i++) c = getc(fp);
{ /* COLOUR SEQUENCE ENDS in 'm' */
c = getc(fp); if (c == 'm') {
if (c == 'm') //COLOUR SEQUENCE ENDS in 'm' buf[i] = '\0';
{ break;
buf[i] = '\0'; }
break; if (c < '0' && c > '9' && c != ';') {
} while (--i >= 0)
if (c < '0' && c > '9' && c != ';') ungetc(buf[i], fp);
{ return;
while(--i >= 0) }
ungetc(buf[i],fp); buf[i] = (char)c;
return; }
} num1 = strtol(buf, &nextnum, 10);
buf[i] = (char)c; if (nextnum != buf && nextnum[0] != '\0')
} num2 = strtol(nextnum + 1, NULL, 10);
num1 = strtol(buf, &nextnum, 10); else
if (nextnum != buf && nextnum[0] != '\0') num2 = -1;
num2 = strtol(nextnum+1, NULL, 10); set_ansi_attribute(num1);
else set_ansi_attribute(num2);
num2 = -1;
set_ansi_attribute(num1);
set_ansi_attribute(num2);
} }
static void do_usage(void) NORETURN; static void __attribute__ ((__noreturn__)) do_exit(int status)
static void do_usage(void)
{
fprintf(stderr, usage, progname);
exit(1);
}
static void do_exit(int status) NORETURN;
static void do_exit(int status)
{ {
if (curses_started) if (curses_started)
endwin(); endwin();
@ -151,17 +147,13 @@ static void do_exit(int status)
} }
/* signal handler */ /* signal handler */
static void die(int notused) NORETURN; static void die(int notused __attribute__ ((__unused__)))
static void die(int notused)
{ {
(void) notused; do_exit(EXIT_SUCCESS);
do_exit(0);
} }
static void static void winch_handler(int notused __attribute__ ((__unused__)))
winch_handler(int notused)
{ {
(void) notused;
screen_size_changed = 1; screen_size_changed = 1;
} }
@ -170,46 +162,53 @@ static char env_row_buf[24];
static int incoming_cols; static int incoming_cols;
static int incoming_rows; static int incoming_rows;
static void static void get_terminal_size(void)
get_terminal_size(void)
{ {
struct winsize w; struct winsize w;
if(!incoming_cols){ // have we checked COLUMNS? if (!incoming_cols) {
/* have we checked COLUMNS? */
const char *s = getenv("COLUMNS"); const char *s = getenv("COLUMNS");
incoming_cols = -1; incoming_cols = -1;
if(s && *s){ if (s && *s) {
long t; long t;
char *endptr; char *endptr;
t = strtol(s, &endptr, 0); 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; 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); putenv(env_col_buf);
} }
} }
if(!incoming_rows){ // have we checked LINES? if (!incoming_rows) {
/* have we checked LINES? */
const char *s = getenv("LINES"); const char *s = getenv("LINES");
incoming_rows = -1; incoming_rows = -1;
if(s && *s){ if (s && *s) {
long t; long t;
char *endptr; char *endptr;
t = strtol(s, &endptr, 0); 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; 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); 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 (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; 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); putenv(env_row_buf);
} }
if (incoming_cols<0 && w.ws_col > 0){ if (incoming_cols < 0 && w.ws_col > 0) {
width = w.ws_col; 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); putenv(env_col_buf);
} }
} }
@ -219,180 +218,186 @@ get_terminal_size(void)
/* get current time in usec */ /* get current time in usec */
typedef unsigned long long watch_usec_t; typedef unsigned long long watch_usec_t;
#define USECS_PER_SEC (1000000ull) #define USECS_PER_SEC (1000000ull)
watch_usec_t get_time_usec() { watch_usec_t get_time_usec()
{
struct timeval now; struct timeval now;
gettimeofday(&now, NULL); 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 #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 #define MAX_ENC_BYTES 16
wint_t my_getwc(FILE *s); wint_t my_getwc(FILE * s);
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 {
/* assuming no encoding ever consumes more than 16 bytes */
char i[MAX_ENC_BYTES];
int byte = 0; int byte = 0;
int convert; int convert;
int x; int x;
wchar_t rval; wchar_t rval;
while(1) { while (1) {
i[byte] = getc(s); i[byte] = getc(s);
if (i[byte]==EOF) { return WEOF; } if (i[byte] == EOF) {
return WEOF;
}
byte++; byte++;
errno = 0; errno = 0;
mbtowc(NULL, NULL, 0); mbtowc(NULL, NULL, 0);
convert = mbtowc(&rval, i, byte); convert = mbtowc(&rval, i, byte);
x = errno; x = errno;
if(convert > 0) { return rval; } //legal conversion if (convert > 0) {
if(byte == MAX_ENC_BYTES) { /* legal conversion */
while(byte > 1) { ungetc(i[--byte], s); } //at least *try* to fix up return rval;
errno = -EILSEQ; }
return WEOF; 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 int main(int argc, char *argv[])
main(int argc, char *argv[])
{ {
int optc; int optc;
int option_differences = 0, int option_differences = 0,
option_differences_cumulative = 0, option_differences_cumulative = 0,
option_exec = 0, option_exec = 0,
option_beep = 0, option_beep = 0,
option_color = 0, option_color = 0,
option_errexit = 0, option_errexit = 0, option_help = 0, option_version = 0;
option_help = 0, option_version = 0;
double interval = 2; double interval = 2;
char *command; char *command;
char **command_argv; char **command_argv;
int command_length = 0; /* not including final \0 */ int command_length = 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 */
#ifdef WITH_WATCH8BIT #ifdef WITH_WATCH8BIT
wchar_t *wcommand = NULL; wchar_t *wcommand = NULL;
int wcommand_columns = 0; /* not including final \0 */ int wcommand_columns = 0; /* not including final \0 */
int wcommand_characters = 0; /* not including final \0 */ int wcommand_characters = 0; /* not including final \0 */
#endif /* WITH_WATCH8BIT */ #endif /* WITH_WATCH8BIT */
int pipefd[2]; int pipefd[2];
int status; int status;
pid_t child; pid_t child;
setlocale(LC_ALL, ""); static struct option longopts[] = {
progname = argv[0]; {"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) { != EOF) {
switch (optc) { switch (optc) {
case 'b': case 'b':
option_beep = 1; option_beep = 1;
break; break;
case 'c': case 'c':
option_color = 1; option_color = 1;
break; break;
case 'd': case 'd':
option_differences = 1; option_differences = 1;
if (optarg) if (optarg)
option_differences_cumulative = 1; option_differences_cumulative = 1;
break; break;
case 'e': case 'e':
option_errexit = 1; option_errexit = 1;
break;
case 'h':
option_help = 1;
break; break;
case 't': case 't':
show_title = 0; show_title = 0;
break; break;
case 'x': case 'x':
option_exec = 1; option_exec = 1;
break; break;
case 'n': case 'n':
{ {
char *str; char *str;
interval = strtod(optarg, &str); interval = strtod(optarg, &str);
if (!*optarg || *str) if (!*optarg || *str)
do_usage(); usage(stderr);
if(interval < 0.1) if (interval < 0.1)
interval = 0.1; interval = 0.1;
if(interval > ~0u/1000000) if (interval > ~0u / 1000000)
interval = ~0u/1000000; interval = ~0u / 1000000;
} }
break; break;
case 'p': case 'p':
precise_timekeeping = 1; precise_timekeeping = 1;
break; break;
case 'v': case 'h':
option_version = 1; usage(stdout);
break; break;
case 'v':
display_version();
return EXIT_SUCCESS;
default: default:
do_usage(); usage(stderr);
break; 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=<seconds>\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) 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 = strdup(argv[optind++]);
command_length = strlen(command); command_length = strlen(command);
for (; optind < argc; optind++) { for (; optind < argc; optind++) {
char *endp; char *endp;
int s = strlen(argv[optind]); 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 = command + command_length;
*endp = ' '; *endp = ' ';
memcpy(endp + 1, argv[optind], s); 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'; command[command_length] = '\0';
} }
#ifdef WITH_WATCH8BIT #ifdef WITH_WATCH8BIT
// convert to wide for printing purposes /* convert to wide for printing purposes */
//mbstowcs(NULL, NULL, 0); /*mbstowcs(NULL, NULL, 0); */
wcommand_characters = mbstowcs(NULL, command, 0); wcommand_characters = mbstowcs(NULL, command, 0);
if(wcommand_characters < 0) { if (wcommand_characters < 0) {
fprintf(stderr, "Unicode Handling Error\n"); fprintf(stderr, "Unicode Handling Error\n");
exit(1); exit(EXIT_FAILURE);
} }
wcommand = (wchar_t*)malloc((wcommand_characters+1) * sizeof(wcommand)); wcommand =
if(wcommand == NULL) { (wchar_t *) malloc((wcommand_characters + 1) * sizeof(wcommand));
if (wcommand == NULL) {
fprintf(stderr, "Unicode Handling Error (malloc)\n"); 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); wcommand_columns = wcswidth(wcommand, -1);
#endif /* WITH_WATCH8BIT */ #endif /* WITH_WATCH8BIT */
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. */
signal(SIGINT, die); signal(SIGINT, die);
signal(SIGTERM, die); signal(SIGTERM, die);
signal(SIGHUP, die); signal(SIGHUP, die);
@ -401,14 +406,14 @@ main(int argc, char *argv[])
/* Set up tty for curses use. */ /* Set up tty for curses use. */
curses_started = 1; curses_started = 1;
initscr(); initscr();
if (option_color) { if (option_color) {
if (has_colors()) { if (has_colors()) {
start_color(); start_color();
use_default_colors(); use_default_colors();
init_ansi_colors(); init_ansi_colors();
} else } else
option_color = 0; option_color = 0;
} }
nonl(); nonl();
noecho(); noecho();
cbreak(); cbreak();
@ -435,44 +440,70 @@ main(int argc, char *argv[])
} }
if (show_title) { 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); int hlen = asprintf(&header, "Every %.1fs: ", interval);
// the rules: /*
// width < tsl : print nothing * the rules:
// width < tsl + hlen + 1: print ts * width < tsl : print nothing
// width = tsl + hlen + 1: print header, ts * width < tsl + hlen + 1: print ts
// width < tsl + hlen + 4: print header, ..., ts * width = tsl + hlen + 1: print header, ts
// width < tsl + hlen + wcommand_columns: print header, truncated wcommand, ..., ts * width < tsl + hlen + 4: print header, ..., ts
// width > "": print header, wcomand, ts * width < tsl + hlen + wcommand_columns: print
// this is slightly different from how it used to be * header, truncated wcommand,
if(width >= tsl) { * ..., ts
if(width >= tsl + hlen + 1) { * 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(width >= tsl + hlen + 2) { if (width >= tsl + hlen + 2) {
if(width < tsl + hlen + 4) { if (width < tsl + hlen + 4) {
mvaddstr(0, width - tsl - 4, "... "); mvaddstr(0,
}else{ width - tsl -
4, "... ");
} else {
#ifdef WITH_WATCH8BIT #ifdef WITH_WATCH8BIT
if(width < tsl + hlen + wcommand_columns) { if (width <
// print truncated tsl + hlen +
wcommand_columns) {
/* print truncated */
int avail_columns = width - tsl - hlen; int avail_columns = width - tsl - hlen;
int using_columns = wcommand_columns; int using_columns = wcommand_columns;
int using_characters = wcommand_characters; int using_characters = wcommand_characters;
while(using_columns > avail_columns - 4) { while (using_columns > avail_columns - 4) {
using_characters--; using_characters--;
using_columns = wcswidth(wcommand, using_characters); using_columns
=
wcswidth
(wcommand,
using_characters);
} }
mvaddnwstr(0, hlen, wcommand, using_characters); mvaddnwstr(0,
mvaddstr(0, width - tsl - 4, "... "); hlen,
}else{ wcommand,
mvaddwstr(0, hlen, wcommand); using_characters);
mvaddstr(0,
width -
tsl -
4,
"... ");
} else {
mvaddwstr(0,
hlen,
wcommand);
} }
#else #else
mvaddnstr(0, hlen, command, width - tsl - hlen); mvaddnstr(0, hlen,
#endif /* WITH_WATCH8BIT */ command,
width - tsl -
hlen);
#endif /* WITH_WATCH8BIT */
} }
} }
} }
@ -483,101 +514,99 @@ main(int argc, char *argv[])
} }
/* allocate pipes */ /* allocate pipes */
if (pipe(pipefd)<0) { if (pipe(pipefd) < 0)
perror("pipe"); err(7, "pipe");
do_exit(7);
}
/* flush stdout and stderr, since we're about to do fd stuff */ /* flush stdout and stderr, since we're about to do fd stuff */
fflush(stdout); fflush(stdout);
fflush(stderr); fflush(stderr);
/* fork to prepare to run command */ /* fork to prepare to run command */
child=fork(); child = fork();
if (child<0) { /* fork error */ if (child < 0) { /* fork error */
perror("fork"); err(2, "fork");
do_exit(2); } else if (child == 0) { /* in child */
} else if (child==0) { /* in child */ close(pipefd[0]); /* child doesn't need read side of pipe */
close (pipefd[0]); /* child doesn't need read side of pipe */ close(1); /* prepare to replace stdout with pipe */
close (1); /* prepare to replace stdout with pipe */ if (dup2(pipefd[1], 1) < 0) { /* replace stdout with write side of pipe */
if (dup2 (pipefd[1], 1)<0) { /* replace stdout with write side of pipe */ err(3, "dup2");
perror("dup2");
exit(3);
} }
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 (option_exec) { /* pass command to exec instead of system */
if (execvp(command_argv[0], command_argv)==-1) { if (execvp(command_argv[0], command_argv) == -1) {
perror("exec"); err(4, "exec");
exit(4);
} }
} else { } 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 */ /* propagate command exit status as child exit status */
if (!WIFEXITED(status)) { /* child exits nonzero if command does */ if (!WIFEXITED(status)) { /* child exits nonzero if command does */
exit(1); exit(EXIT_FAILURE);
} else { } else {
exit(WEXITSTATUS(status)); exit(WEXITSTATUS(status));
} }
} }
} }
/* otherwise, we're in parent */ /* otherwise, we're in parent */
close(pipefd[1]); /* close write side of pipe */ close(pipefd[1]); /* close write side of pipe */
if ((p=fdopen(pipefd[0], "r"))==NULL) { if ((p = fdopen(pipefd[0], "r")) == NULL)
perror("fdopen"); err(5, "fdopen");
do_exit(5);
}
for (y = show_title; y < height; y++) { for (y = show_title; y < height; y++) {
int eolseen = 0, tabpending = 0; int eolseen = 0, tabpending = 0;
#ifdef WITH_WATCH8BIT #ifdef WITH_WATCH8BIT
wint_t carry = WEOF; wint_t carry = WEOF;
#endif /* WITH_WATCH8BIT */ #endif /* WITH_WATCH8BIT */
for (x = 0; x < width; x++) { for (x = 0; x < width; x++) {
#ifdef WITH_WATCH8BIT #ifdef WITH_WATCH8BIT
wint_t c = ' '; wint_t c = ' ';
#else #else
int c = ' '; int c = ' ';
#endif /* WITH_WATCH8BIT */ #endif /* WITH_WATCH8BIT */
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
next stop instead of reading characters */ * spit spaces until the next stop
if (!tabpending) * instead of reading characters */
if (!tabpending)
#ifdef WITH_WATCH8BIT #ifdef WITH_WATCH8BIT
do { do {
if(carry == WEOF) { if (carry == WEOF) {
c = my_getwc(p); c = my_getwc(p);
}else{ } else {
c = carry; c = carry;
carry = WEOF; carry = WEOF;
} }
}while (c != WEOF && !isprint(c) && c<12 } while (c != WEOF
&& wcwidth(c) == 0 && !isprint(c)
&& c != L'\n' && c < 12
&& c != L'\t' && wcwidth(c) == 0
&& (c != L'\033' || option_color != 1)); && c != L'\n'
&& c != L'\t'
&& (c != L'\033'
|| option_color !=
1));
#else #else
do do
c = getc(p); c = getc(p);
while (c != EOF && !isprint(c) while (c != EOF && !isprint(c)
&& c != '\n' && c != '\n'
&& c != '\t' && c != '\t'
&& (c != L'\033' || option_color != 1)); && (c != L'\033'
#endif /* WITH_WATCH8BIT */ || option_color !=
if (c == L'\033' && option_color == 1) { 1));
x--; #endif /* WITH_WATCH8BIT */
process_ansi(p); if (c == L'\033' && option_color == 1) {
continue; x--;
} process_ansi(p);
if (c == L'\n') continue;
}
if (c == L'\n')
if (!oldeolseen && x == 0) { if (!oldeolseen && x == 0) {
x = -1; x = -1;
continue; continue;
@ -586,31 +615,33 @@ main(int argc, char *argv[])
else if (c == L'\t') else if (c == L'\t')
tabpending = 1; tabpending = 1;
#ifdef WITH_WATCH8BIT #ifdef WITH_WATCH8BIT
if (x==width-1 && wcwidth(c)==2) { if (x == width - 1 && wcwidth(c) == 2) {
y++; y++;
x = -1; //process this double-width x = -1; /* process this double-width */
carry = c; //character on the next line carry = c; /* character on the next line */
continue; //because it won't fit here continue; /* because it won't fit here */
} }
if (c == WEOF || c == L'\n' || c == L'\t') if (c == WEOF || c == L'\n'
c = L' '; || c == L'\t')
c = L' ';
#else #else
if (c == EOF || c == '\n' || c == '\t') if (c == EOF || c == '\n' || c == '\t')
c = ' '; c = ' ';
#endif /* WITH_WATCH8BIT */ #endif /* WITH_WATCH8BIT */
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) {
#ifdef WITH_WATCH8BIT #ifdef WITH_WATCH8BIT
cchar_t oldc; cchar_t oldc;
in_wch(&oldc); in_wch(&oldc);
attr = !first_screen attr = !first_screen
&& ((wchar_t)c != oldc.chars[0] && ((wchar_t) c != oldc.chars[0]
|| ||
(option_differences_cumulative (option_differences_cumulative
&& (oldc.attr & A_ATTRIBUTES))); && (oldc.
attr & A_ATTRIBUTES)));
#else #else
chtype oldch = inch(); chtype oldch = inch();
unsigned char oldc = oldch & A_CHARTEXT; unsigned char oldc = oldch & A_CHARTEXT;
@ -619,21 +650,25 @@ main(int argc, char *argv[])
|| ||
(option_differences_cumulative (option_differences_cumulative
&& (oldch & A_ATTRIBUTES))); && (oldch & A_ATTRIBUTES)));
#endif /* WITH_WATCH8BIT */ #endif /* WITH_WATCH8BIT */
} }
if (attr) if (attr)
standout(); standout();
#ifdef WITH_WATCH8BIT #ifdef WITH_WATCH8BIT
addnwstr((wchar_t*)&c,1); addnwstr((wchar_t *) & c, 1);
#else #else
addch(c); addch(c);
#endif /* WITH_WATCH8BIT */ #endif /* WITH_WATCH8BIT */
if (attr) if (attr)
standend(); standend();
#ifdef WITH_WATCH8BIT #ifdef WITH_WATCH8BIT
if(wcwidth(c) == 0) { x--; } if (wcwidth(c) == 0) {
if(wcwidth(c) == 2) { x++; } x--;
#endif /* WITH_WATCH8BIT */ }
if (wcwidth(c) == 2) {
x++;
}
#endif /* WITH_WATCH8BIT */
} }
oldeolseen = eolseen; oldeolseen = eolseen;
} }
@ -641,29 +676,29 @@ main(int argc, char *argv[])
fclose(p); fclose(p);
/* harvest child process and get status, propagated from command */ /* harvest child process and get status, propagated from command */
if (waitpid(child, &status, 0)<0) { if (waitpid(child, &status, 0) < 0)
perror("waitpid"); err(8, "waitpid");
do_exit(8);
};
/* if child process exited in error, beep if option_beep is set */ /* if child process exited in error, beep if option_beep is set */
if ((!WIFEXITED(status) || WEXITSTATUS(status))) { if ((!WIFEXITED(status) || WEXITSTATUS(status))) {
if (option_beep) beep(); if (option_beep)
if (option_errexit) do_exit(8); beep();
if (option_errexit)
exit(8);
} }
first_screen = 0; first_screen = 0;
refresh(); refresh();
if (precise_timekeeping) { if (precise_timekeeping) {
watch_usec_t cur_time = get_time_usec(); 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) if (cur_time < next_loop)
usleep(next_loop - cur_time); usleep(next_loop - cur_time);
} else } else
usleep(interval * 1000000); usleep(interval * 1000000);
} }
endwin(); endwin();
return 0; return EXIT_SUCCESS;
} }