Merge remote-tracking branch 'sami/2012wk12'

Conflicts:
	watch.c
This commit is contained in:
Craig Small 2012-04-15 10:44:37 +10:00
commit 09d67d5ab2
26 changed files with 443 additions and 359 deletions

View File

@ -25,8 +25,6 @@ usrbin_exec_PROGRAMS = \
pkill \
pmap \
pwdx \
skill \
snice \
tload \
uptime \
vmstat \
@ -38,8 +36,6 @@ dist_man_MANS = \
pkill.1 \
pmap.1 \
pwdx.1 \
skill.1 \
snice.1 \
sysctl.8 \
sysctl.conf.5 \
tload.1 \
@ -50,6 +46,7 @@ dist_man_MANS = \
if BUILD_KILL
bin_PROGRAMS = kill
dist_man_MANS += kill.1
kill_SOURCES = skill.c $(top_srcdir)/lib/strutils.c $(top_srcdir)/lib/fileutils.c
endif
if WITH_NCURSES
@ -59,19 +56,33 @@ usrbin_exec_PROGRAMS += \
dist_man_MANS += \
slabtop.1 \
watch.1
slabtop_SOURCES = slabtop.c $(top_srcdir)/lib/strutils.c
slabtop_SOURCES = slabtop.c $(top_srcdir)/lib/strutils.c $(top_srcdir)/lib/fileutils.c
slabtop_LDADD = @NCURSES_LIBS@
watch_SOURCES = watch.c $(top_srcdir)/lib/strutils.c
watch_SOURCES = watch.c $(top_srcdir)/lib/strutils.c $(top_srcdir)/lib/fileutils.c
watch_LDADD = @WATCH_NCURSES_LIBS@
endif
kill_SOURCES = skill.c $(top_srcdir)/lib/strutils.c
skill_SOURCES = skill.c $(top_srcdir)/lib/strutils.c
snice_SOURCES = skill.c $(top_srcdir)/lib/strutils.c
tload_SOURCES = tload.c $(top_srcdir)/lib/strutils.c
pkill_SOURCES = pgrep.c
free_SOURCES = free.c $(top_srcdir)/lib/strutils.c
vmstat_SOURCES = vmstat.c $(top_srcdir)/lib/strutils.c
if BUILD_SKILL
usrbin_exec_PROGRAMS += \
skill \
snice
skill_SOURCES = skill.c $(top_srcdir)/lib/strutils.c $(top_srcdir)/lib/fileutils.c
snice_SOURCES = skill.c $(top_srcdir)/lib/strutils.c $(top_srcdir)/lib/fileutils.c
dist_man_MANS += \
skill.1 \
snice.1
endif
free_SOURCES = free.c $(top_srcdir)/lib/strutils.c $(top_srcdir)/lib/fileutils.c
pgrep_SOURCES = pgrep.c $(top_srcdir)/lib/fileutils.c
pkill_SOURCES = pgrep.c $(top_srcdir)/lib/fileutils.c
pmap_SOURCES = pmap.c $(top_srcdir)/lib/fileutils.c
pwdx_SOURCES = pwdx.c $(top_srcdir)/lib/fileutils.c
sysctl_SOURCES = sysctl.c $(top_srcdir)/lib/fileutils.c
tload_SOURCES = tload.c $(top_srcdir)/lib/strutils.c $(top_srcdir)/lib/fileutils.c
uptime_SOURCES = uptime.c $(top_srcdir)/lib/fileutils.c
vmstat_SOURCES = vmstat.c $(top_srcdir)/lib/strutils.c $(top_srcdir)/lib/fileutils.c
w_SOURCES = w.c $(top_srcdir)/lib/fileutils.c
sysconf_DATA = sysctl.conf

View File

@ -179,6 +179,12 @@ AC_ARG_ENABLE([kill],
AM_CONDITIONAL(BUILD_KILL, test "x$enable_kill" = xyes)
AM_CONDITIONAL(LINUX, test "x$host_os" = xlinux-gnu)
AC_ARG_ENABLE([skill],
AS_HELP_STRING([--enable-skill], [build skill and snice]),
[], enable_skill=no
)
AM_CONDITIONAL(BUILD_SKILL, test "x$build_skill" = xyes)
AC_ARG_ENABLE([oomem],
AS_HELP_STRING([--enable-oomem], [add out-of-memory fields to the library and top]),
[], enable_oomem=no

2
free.c
View File

@ -32,6 +32,7 @@
#include "c.h"
#include "nls.h"
#include "strutils.h"
#include "fileutils.h"
#include <locale.h>
#include <errno.h>
@ -226,6 +227,7 @@ int main(int argc, char **argv)
setlocale (LC_ALL, "");
bindtextdomain(PACKAGE, LOCALEDIR);
textdomain(PACKAGE);
atexit(close_stdout);
while ((c = getopt_long(argc, argv, "bkmghlotc:s:V", longopts, NULL)) != -1)
switch (c) {

7
include/fileutils.h Normal file
View File

@ -0,0 +1,7 @@
#ifndef PROCPS_NG_FILEUTILS
#define PROCPS_NG_FILEUTILS
int close_stream(FILE * stream);
void close_stdout(void);
#endif

1
lib/.gitignore vendored
View File

@ -1,2 +1,3 @@
.dirstamp
test_fileutils
test_strutils

View File

@ -2,6 +2,7 @@ AM_CPPFLAGS = -include $(top_builddir)/config.h -I$(top_srcdir)/include
AM_CPPFLAGS += -DTEST_PROGRAM
noinst_PROGRAMS = test_strutils
noinst_PROGRAMS = test_strutils test_fileutils
test_strutils_SOURCES = strutils.c
test_fileutils_SOURCES = fileutils.c

43
lib/fileutils.c Normal file
View File

@ -0,0 +1,43 @@
#include <errno.h>
#include <error.h>
#include <stdio_ext.h>
#include <stdlib.h>
#include <unistd.h>
#include "nls.h"
int close_stream(FILE * stream)
{
const int some_pending = (__fpending(stream) != 0);
const int prev_fail = (ferror(stream) != 0);
const int fclose_fail = (fclose(stream) != 0);
if (prev_fail || (fclose_fail && (some_pending || errno != EBADF))) {
if (!fclose_fail)
errno = 0;
return EOF;
}
return 0;
}
/* Use atexit(); */
void close_stdout(void)
{
if (close_stream(stdout) != 0 && !(errno == EPIPE)) {
char const *write_error = _("write error");
error(0, errno, "%s", write_error);
_exit(EXIT_FAILURE);
}
if (close_stream(stderr) != 0)
_exit(EXIT_FAILURE);
}
#ifdef TEST_PROGRAM
#include <stdio.h>
int main(int argc, char *argv[])
{
atexit(close_stdout);
printf("Hello, World!\n");
return EXIT_SUCCESS;
}
#endif /* TEST_PROGRAM */

View File

@ -42,6 +42,7 @@
#define XALLOC_EXIT_CODE EXIT_FATAL
#include "c.h"
#include "fileutils.h"
#include "nls.h"
#include "xalloc.h"
#include "proc/readproc.h"
@ -791,6 +792,7 @@ int main (int argc, char **argv)
setlocale (LC_ALL, "");
bindtextdomain(PACKAGE, LOCALEDIR);
textdomain(PACKAGE);
atexit(close_stdout);
parse_opts (argc, argv);

2
pmap.c
View File

@ -31,6 +31,7 @@
#include <unistd.h>
#include "c.h"
#include "fileutils.h"
#include "nls.h"
#include "proc/escape.h"
#include "xalloc.h"
@ -426,6 +427,7 @@ int main(int argc, char **argv)
setlocale (LC_ALL, "");
bindtextdomain(PACKAGE, LOCALEDIR);
textdomain(PACKAGE);
atexit(close_stdout);
x_option = d_option = q_option = 0;

View File

@ -21,7 +21,8 @@ pscommand_SOURCES = \
parser.c \
select.c \
sortformat.c \
stacktrace.c
stacktrace.c \
$(top_srcdir)/lib/fileutils.c
EXTRA_DIST = \
HACKING \

View File

@ -36,6 +36,7 @@
#include "../proc/version.h"
#include "../proc/wchan.h"
#include "../include/fileutils.h"
#include "common.h"
#ifndef SIGCHLD
@ -531,6 +532,7 @@ static void fancy_spew(void){
/***** no comment */
int main(int argc, char *argv[]){
atexit(close_stdout);
myname = strrchr(*argv, '/');
if (myname) ++myname; else myname = *argv;

2
pwdx.c
View File

@ -30,6 +30,7 @@
#include "c.h"
#include "nls.h"
#include "xalloc.h"
#include "fileutils.h"
static void __attribute__ ((__noreturn__)) usage(FILE * out)
{
@ -77,6 +78,7 @@ int main(int argc, char *argv[])
setlocale (LC_ALL, "");
bindtextdomain(PACKAGE, LOCALEDIR);
textdomain(PACKAGE);
atexit(close_stdout);
while ((ch = getopt_long(argc, argv, "Vh", longopts, NULL)) != -1)
switch (ch) {

27
skill.c
View File

@ -35,6 +35,7 @@
#include <unistd.h>
#include "c.h"
#include "fileutils.h"
#include "strutils.h"
#include "nls.h"
#include "xalloc.h"
@ -375,6 +376,7 @@ static void __attribute__ ((__noreturn__))
setlocale (LC_ALL, "");
bindtextdomain(PACKAGE, LOCALEDIR);
textdomain(PACKAGE);
atexit(close_stdout);
if (argc < 2)
kill_usage(stderr);
@ -473,9 +475,7 @@ static void skillsnice_parse(int argc,
{
int signo = -1;
int prino = DEFAULT_NICE;
int num_found = 0;
int ch, i;
const char *restrict argptr;
static const struct option longopts[] = {
{"command", required_argument, NULL, 'c'},
@ -545,30 +545,10 @@ static void skillsnice_parse(int argc,
{
struct stat sbuf;
char path[32];
if (!optarg)
/* Huh? Maybe "skill -t ''". */
skillsnice_usage(stderr);
snprintf(path, 32, "/dev/%s", optarg);
if (stat(path, &sbuf) >= 0
&& S_ISCHR(sbuf.st_mode)) {
num_found++;
ENLIST(tty, sbuf.st_rdev);
if (!NEXTARG)
break;
} else if (optarg && !(optarg[1])) {
/* if only 1 character */
switch (*optarg) {
default:
if (stat(optarg, &sbuf) < 0)
/* the shell eats '?' */
break;
case '-':
case '?':
num_found++;
ENLIST(tty, 0);
if (!NEXTARG)
break;
}
}
}
break;
@ -577,10 +557,7 @@ static void skillsnice_parse(int argc,
struct passwd *passwd_data;
passwd_data = getpwnam(optarg);
if (passwd_data) {
num_found++;
ENLIST(uid, passwd_data->pw_uid);
if (!NEXTARG)
break;
}
}
break;

View File

@ -39,6 +39,7 @@
#include <unistd.h>
#include "c.h"
#include "fileutils.h"
#include "nls.h"
#include "strutils.h"
#include "proc/slab.h"
@ -303,6 +304,7 @@ int main(int argc, char *argv[])
setlocale (LC_ALL, "");
bindtextdomain(PACKAGE, LOCALEDIR);
textdomain(PACKAGE);
atexit(close_stdout);
sort_func = DEF_SORT_FUNC;
@ -414,7 +416,7 @@ int main(int argc, char *argv[])
tv.tv_sec = delay;
tv.tv_usec = 0;
if (select(STDOUT_FILENO, &readfds, NULL, NULL, &tv) > 0) {
if (read(0, &c, 1) != 1)
if (read(STDIN_FILENO, &c, 1) != 1)
break;
parse_input(c);
}

View File

@ -40,6 +40,7 @@
#include <unistd.h>
#include "c.h"
#include "fileutils.h"
#include "nls.h"
#include "xalloc.h"
#include "proc/procps.h"
@ -442,14 +443,10 @@ static int WriteSetting(const char *setting)
}
} else {
rc = fprintf(fp, "%s\n", value);
if (rc < 0) {
if (0 < rc)
rc = 0;
if (close_stream(fp) != 0)
xwarn(_("setting key \"%s\""), outname);
fclose(fp);
} else {
rc = fclose(fp);
if (rc != 0)
xwarn(_("setting key \"%s\""), outname);
}
if (rc == 0 && !Quiet) {
if (NameOnly) {
fprintf(stdout, "%s\n", outname);
@ -675,6 +672,7 @@ int main(int argc, char *argv[])
setlocale(LC_ALL, "");
bindtextdomain(PACKAGE, LOCALEDIR);
textdomain(PACKAGE);
atexit(close_stdout);
PrintName = true;
PrintNewline = true;

View File

@ -20,6 +20,7 @@ DEJATOOL += \
DEJATOOL += \
free \
lib \
pgrep \
pkill \
ps \
@ -34,6 +35,7 @@ EXTRA_DIST = \
global-conf.exp \
free.test/free.exp \
kill.test/kill.exp \
lib.test/fileutils.exp \
lib.test/strutils.exp \
pgrep.test/pgrep.exp \
pkill.test/pkill.exp \

View File

@ -0,0 +1,19 @@
#
# Testsuite for lib/fileutils program
#
set noarg "${topdir}lib/test_fileutils"
set test "without argument"
spawn $noarg
expect_pass "$test" "Hello, World!"
set badfd "${topdir}testsuite/lib.test/fileutils_badfd.sh"
set test "test bad file descriptor"
spawn $badfd
expect_pass "$test" "test_fileutils: write error: Bad file descriptor"
set full "${topdir}testsuite/lib.test/fileutils_full.sh"
set test "test no space left on device"
spawn $full
expect_pass "$test" "test_fileutils: write error: No space left on device"

View File

@ -0,0 +1,4 @@
#!/bin/sh
BASEDIR=$(dirname ${0})
${BASEDIR}/../../lib/test_fileutils >&-

View File

@ -0,0 +1,4 @@
#!/bin/sh
BASEDIR=$(dirname ${0})
${BASEDIR}/../../lib/test_fileutils > /dev/full

View File

@ -27,6 +27,7 @@
#include "proc/version.h"
#include "proc/sysinfo.h"
#include "c.h"
#include "fileutils.h"
#include "nls.h"
#include "strutils.h"
#include "xalloc.h"
@ -117,6 +118,7 @@ int main(int argc, char **argv)
setlocale (LC_ALL, "");
bindtextdomain(PACKAGE, LOCALEDIR);
textdomain(PACKAGE);
atexit(close_stdout);
while ((opt =
getopt_long(argc, argv, "s:d:Vh", longopts, NULL)) != -1)

View File

@ -13,7 +13,8 @@ top_SOURCES = \
top.h \
top.c \
top_nls.h \
top_nls.c
top_nls.c \
$(top_srcdir)/lib/fileutils.c
dist_man_MANS = \
top.1

View File

@ -41,6 +41,7 @@
#include <unistd.h>
#include <values.h>
#include "../include/fileutils.h"
#include "../include/nls.h"
#include "../proc/devname.h"
@ -3901,6 +3902,7 @@ static void frame_make (void) {
* duh... */
int main (int dont_care_argc, char **argv) {
(void)dont_care_argc;
atexit(close_stdout);
before(*argv);
// +-------------+
wins_stage_1(); // top (sic) slice

View File

@ -23,6 +23,7 @@
#include <stdio.h>
#include "c.h"
#include "fileutils.h"
#include "nls.h"
#include "proc/whattime.h"
#include "proc/version.h"
@ -53,6 +54,7 @@ int main(int argc, char **argv)
setlocale (LC_ALL, "");
bindtextdomain(PACKAGE, LOCALEDIR);
textdomain(PACKAGE);
atexit(close_stdout);
while ((c = getopt_long(argc, argv, "hV", longopts, NULL)) != -1)
switch (c) {

View File

@ -45,6 +45,7 @@
#include <unistd.h>
#include "c.h"
#include "fileutils.h"
#include "nls.h"
#include "strutils.h"
#include "proc/sysinfo.h"
@ -694,7 +695,7 @@ static int winhi(void)
struct winsize win;
int rows = 24;
if (ioctl(1, TIOCGWINSZ, &win) != -1 && win.ws_row > 0)
if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &win) != -1 && 0 < win.ws_row)
rows = win.ws_row;
return rows;
@ -725,6 +726,7 @@ int main(int argc, char *argv[])
setlocale (LC_ALL, "");
bindtextdomain(PACKAGE, LOCALEDIR);
textdomain(PACKAGE);
atexit(close_stdout);
while ((c =
getopt_long(argc, argv, "afmnsdDp:S:hV", longopts,

2
w.c
View File

@ -24,6 +24,7 @@
*/
#include "c.h"
#include "fileutils.h"
#include "nls.h"
#include "proc/devname.h"
#include "proc/escape.h"
@ -356,6 +357,7 @@ int main(int argc, char **argv)
setlocale (LC_ALL, "");
bindtextdomain(PACKAGE, LOCALEDIR);
textdomain(PACKAGE);
atexit(close_stdout);
#ifndef W_SHOWFROM
from = 0;

605
watch.c
View File

@ -29,6 +29,7 @@
#include "c.h"
#include "config.h"
#include "fileutils.h"
#include "nls.h"
#include "proc/procps.h"
#include "strutils.h"
@ -62,8 +63,18 @@
# define isprint(x) ( (x>=' '&&x<='~') || (x>=0xa0) )
#endif
/* Boolean command line options */
static int flags;
#define WATCH_DIFF (1 << 1)
#define WATCH_CUMUL (1 << 2)
#define WATCH_EXEC (1 << 3)
#define WATCH_BEEP (1 << 4)
#define WATCH_COLOR (1 << 5)
#define WATCH_ERREXIT (1 << 6)
#define WATCH_CHGEXIT (1 << 7)
static int curses_started = 0;
static int height = 24, width = 80;
static long 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 */
@ -195,10 +206,10 @@ static void get_terminal_size(void)
long t;
char *endptr;
t = strtol(s, &endptr, 0);
if (!*endptr && (t > 0) && (t < (long)666))
incoming_cols = (int)t;
if (!*endptr && 0 < t)
incoming_cols = t;
width = incoming_cols;
snprintf(env_col_buf, sizeof env_col_buf, "COLUMNS=%d",
snprintf(env_col_buf, sizeof env_col_buf, "COLUMNS=%ld",
width);
putenv(env_col_buf);
}
@ -211,26 +222,26 @@ static void get_terminal_size(void)
long t;
char *endptr;
t = strtol(s, &endptr, 0);
if (!*endptr && (t > 0) && (t < (long)666))
incoming_rows = (int)t;
if (!*endptr && 0 < t)
incoming_rows = t;
height = incoming_rows;
snprintf(env_row_buf, sizeof env_row_buf, "LINES=%d",
snprintf(env_row_buf, sizeof env_row_buf, "LINES=%ld",
height);
putenv(env_row_buf);
}
}
if (incoming_cols < 0 || incoming_rows < 0) {
if (ioctl(2, TIOCGWINSZ, &w) == 0) {
if (ioctl(STDERR_FILENO, TIOCGWINSZ, &w) == 0) {
if (incoming_cols < 0 || incoming_rows < 0) {
if (incoming_rows < 0 && w.ws_row > 0) {
height = w.ws_row;
snprintf(env_row_buf, sizeof env_row_buf,
"LINES=%d", height);
"LINES=%ld", height);
putenv(env_row_buf);
}
if (incoming_cols < 0 && w.ws_col > 0) {
width = w.ws_col;
snprintf(env_col_buf, sizeof env_col_buf,
"COLUMNS=%d", width);
"COLUMNS=%ld", width);
putenv(env_col_buf);
}
}
@ -285,15 +296,268 @@ wint_t my_getwc(FILE * s)
}
#endif /* WITH_WATCH8BIT */
void output_header(char *restrict command, double interval)
{
time_t t = time(NULL);
char *ts = ctime(&t);
int tsl = strlen(ts);
char *header;
/*
* 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) {
free(header);
return;
}
if (tsl + hlen + 1 <= width) {
mvaddstr(0, 0, header);
if (tsl + hlen + 2 <= width) {
if (width < tsl + hlen + 4) {
mvaddstr(0, width - tsl - 4, "... ");
} else {
#ifdef WITH_WATCH8BIT
if (width < tsl + hlen + wcommand_columns) {
/* print truncated */
int available = width - tsl - hlen;
int in_use = wcommand_columns;
int wcomm_len = wcommand_characters;
while (available - 4 < in_use) {
wcomm_len--;
in_use = wcswidth(wcommand, wcomm_len);
}
mvaddnwstr(0, hlen, wcommand, wcomm_len);
mvaddstr(0, width - tsl - 4, "... ");
} else {
mvaddwstr(0, hlen, wcommand);
}
#else
mvaddnstr(0, hlen, command, width - tsl - hlen);
#endif /* WITH_WATCH8BIT */
}
}
}
mvaddstr(0, width - tsl + 1, ts);
free(header);
return;
}
int run_command(char *restrict command, char **restrict command_argv)
{
FILE *p;
int x, y;
int oldeolseen = 1;
int pipefd[2];
pid_t child;
int exit_early = 0;
int status;
/* allocate pipes */
if (pipe(pipefd) < 0)
xerr(7, _("unable to create IPC pipes"));
/* flush stdout and stderr, since we're about to do fd stuff */
fflush(stdout);
fflush(stderr);
/* fork to prepare to run command */
child = fork();
if (child < 0) { /* fork error */
xerr(2, _("unable to fork process"));
} 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 */
xerr(3, _("dup2 failed"));
}
dup2(1, 2); /* stderr should default to stdout */
if (flags & WATCH_EXEC) { /* pass command to exec instead of system */
if (execvp(command_argv[0], command_argv) == -1) {
xerr(4, _("unable to execute '%s'"),
command_argv[0]);
}
} else {
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(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)
xerr(5, _("fdopen"));
for (y = show_title; y < height; y++) {
int eolseen = 0, tabpending = 0;
#ifdef WITH_WATCH8BIT
wint_t carry = WEOF;
#endif
for (x = 0; x < width; x++) {
#ifdef WITH_WATCH8BIT
wint_t c = ' ';
#else
int c = ' ';
#endif
int attr = 0;
if (!eolseen) {
/* 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'
|| !(flags & WATCH_COLOR)));
#else
do
c = getc(p);
while (c != EOF && !isprint(c)
&& c != '\n'
&& c != '\t'
&& (c != L'\033'
|| !(flags & WATCH_COLOR)));
#endif
if (c == L'\033' && (flags & WATCH_COLOR)) {
x--;
process_ansi(p);
continue;
}
if (c == L'\n')
if (!oldeolseen && x == 0) {
x = -1;
continue;
} else
eolseen = 1;
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' ';
#else
if (c == EOF || c == '\n' || c == '\t')
c = ' ';
#endif
if (tabpending && (((x + 1) % 8) == 0))
tabpending = 0;
}
move(y, x);
if (!first_screen && !exit_early && (flags & WATCH_CHGEXIT)) {
#ifdef WITH_WATCH8BIT
cchar_t oldc;
in_wch(&oldc);
exit_early = (wchar_t) c != oldc.chars[0];
#else
chtype oldch = inch();
unsigned char oldc = oldch & A_CHARTEXT;
exit_early = (unsigned char)c != oldc;
#endif
}
if (flags & WATCH_DIFF) {
#ifdef WITH_WATCH8BIT
cchar_t oldc;
in_wch(&oldc);
attr = !first_screen
&& ((wchar_t) c != oldc.chars[0]
||
((flags & WATCH_CUMUL)
&& (oldc.attr & A_ATTRIBUTES)));
#else
chtype oldch = inch();
unsigned char oldc = oldch & A_CHARTEXT;
attr = !first_screen
&& ((unsigned char)c != oldc
||
((flags & WATCH_CUMUL)
&& (oldch & A_ATTRIBUTES)));
#endif
}
if (attr)
standout();
#ifdef WITH_WATCH8BIT
addnwstr((wchar_t *) & c, 1);
#else
addch(c);
#endif
if (attr)
standend();
#ifdef WITH_WATCH8BIT
if (wcwidth(c) == 0) {
x--;
}
if (wcwidth(c) == 2) {
x++;
}
#endif
}
oldeolseen = eolseen;
}
fclose(p);
/* harvest child process and get status, propagated from command */
if (waitpid(child, &status, 0) < 0)
xerr(8, _("waitpid"));
/* if child process exited in error, beep if option_beep is set */
if ((!WIFEXITED(status) || WEXITSTATUS(status))) {
if (flags & WATCH_BEEP)
beep();
if (flags & WATCH_ERREXIT) {
mvaddstr(height - 1, 0,
_("command exit with a non-zero status, press a key to exit"));
refresh();
fgetc(stdin);
endwin();
exit(8);
}
}
first_screen = 0;
refresh();
return exit_early;
}
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_chgexit = 0;
double interval = 2;
char *command;
char **command_argv;
@ -306,10 +570,6 @@ int main(int argc, char *argv[])
int wcommand_characters = 0; /* not including final \0 */
#endif /* WITH_WATCH8BIT */
int pipefd[2];
int status;
pid_t child;
static struct option longopts[] = {
{"color", no_argument, 0, 'c'},
{"differences", optional_argument, 0, 'd'},
@ -329,33 +589,34 @@ int main(int argc, char *argv[])
setlocale(LC_ALL, "");
bindtextdomain(PACKAGE, LOCALEDIR);
textdomain(PACKAGE);
atexit(close_stdout);
while ((optc =
getopt_long(argc, argv, "+bced::ghn:pvtx", longopts, (int *)0))
!= EOF) {
switch (optc) {
case 'b':
option_beep = 1;
flags |= WATCH_BEEP;
break;
case 'c':
option_color = 1;
flags |= WATCH_COLOR;
break;
case 'd':
option_differences = 1;
flags |= WATCH_DIFF;
if (optarg)
option_differences_cumulative = 1;
flags |= WATCH_CUMUL;
break;
case 'e':
option_errexit = 1;
flags |= WATCH_ERREXIT;
break;
case 'g':
option_chgexit = 1;
flags |= WATCH_CHGEXIT;
break;
case 't':
show_title = 0;
break;
case 'x':
option_exec = 1;
flags |= WATCH_EXEC;
break;
case 'n':
interval = strtod_or_err(optarg, _("failed to parse argument"));
@ -430,13 +691,14 @@ int main(int argc, char *argv[])
/* Set up tty for curses use. */
curses_started = 1;
initscr();
if (option_color) {
if (flags & WATCH_COLOR) {
if (has_colors()) {
start_color();
use_default_colors();
init_ansi_colors();
} else
option_color = 0;
} else {
flags |= WATCH_COLOR;
}
}
nonl();
noecho();
@ -446,14 +708,6 @@ int main(int argc, char *argv[])
next_loop = get_time_usec();
while (1) {
time_t t = time(NULL);
char *ts = ctime(&t);
int tsl = strlen(ts);
char *header;
FILE *p;
int x, y;
int oldeolseen = 1;
if (screen_size_changed) {
get_terminal_size();
resizeterm(height, width);
@ -463,277 +717,11 @@ int main(int argc, char *argv[])
first_screen = 1;
}
if (show_title) {
/*
* left justify interval and command, right
* justify time, clipping all to fit window
* width
*/
int hlen = asprintf(&header, _("Every %.1fs: "), interval);
if (show_title)
output_header(command, 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 {
#ifdef WITH_WATCH8BIT
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);
}
#else
mvaddnstr(0, hlen,
command,
width - tsl -
hlen);
#endif /* WITH_WATCH8BIT */
}
}
}
mvaddstr(0, width - tsl + 1, ts);
}
free(header);
}
/* allocate pipes */
if (pipe(pipefd) < 0)
xerr(7, _("unable to create IPC pipes"));
/* flush stdout and stderr, since we're about to do fd stuff */
fflush(stdout);
fflush(stderr);
/* fork to prepare to run command */
child = fork();
if (child < 0) { /* fork error */
xerr(2, _("unable to fork process"));
} 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 */
xerr(3, _("dup2 failed"));
}
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) {
xerr(4, _("unable to execute '%s'"), command_argv[0]);
}
} else {
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(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)
xerr(5, _("fdopen"));
int exit_early = 0;
for (y = show_title; y < height; y++) {
int eolseen = 0, tabpending = 0;
#ifdef WITH_WATCH8BIT
wint_t carry = WEOF;
#endif /* WITH_WATCH8BIT */
for (x = 0; x < width; x++) {
#ifdef WITH_WATCH8BIT
wint_t c = ' ';
#else
int c = ' ';
#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)
#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));
#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')
if (!oldeolseen && x == 0) {
x = -1;
continue;
} else
eolseen = 1;
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' ';
#else
if (c == EOF || c == '\n' || c == '\t')
c = ' ';
#endif /* WITH_WATCH8BIT */
if (tabpending && (((x + 1) % 8) == 0))
tabpending = 0;
}
move(y, x);
if (!first_screen && !exit_early && option_chgexit) {
#ifdef WITH_WATCH8BIT
cchar_t oldc;
in_wch(&oldc);
exit_early = (wchar_t) c != oldc.chars[0];
#else
chtype oldch = inch();
unsigned char oldc = oldch & A_CHARTEXT;
exit_early = (unsigned char) c != oldc;
#endif /* WITH_WATCH8BIT */
}
if (option_differences) {
#ifdef WITH_WATCH8BIT
cchar_t oldc;
in_wch(&oldc);
attr = !first_screen
&& ((wchar_t) c != oldc.chars[0]
||
(option_differences_cumulative
&& (oldc.
attr & A_ATTRIBUTES)));
#else
chtype oldch = inch();
unsigned char oldc = oldch & A_CHARTEXT;
attr = !first_screen
&& ((unsigned char)c != oldc
||
(option_differences_cumulative
&& (oldch & A_ATTRIBUTES)));
#endif /* WITH_WATCH8BIT */
}
if (attr)
standout();
#ifdef WITH_WATCH8BIT
addnwstr((wchar_t *) & c, 1);
#else
addch(c);
#endif /* WITH_WATCH8BIT */
if (attr)
standend();
#ifdef WITH_WATCH8BIT
if (wcwidth(c) == 0) {
x--;
}
if (wcwidth(c) == 2) {
x++;
}
#endif /* WITH_WATCH8BIT */
}
oldeolseen = eolseen;
}
fclose(p);
/* harvest child process and get status, propagated from command */
if (waitpid(child, &status, 0) < 0)
xerr(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) {
mvaddstr(height - 1, 0,
_("command exit with a non-zero status, press a key to exit"));
refresh();
fgetc(stdin);
endwin();
exit(8);
}
}
first_screen = 0;
refresh();
if (exit_early)
if (run_command(command, command_argv))
break;
if (precise_timekeeping) {
watch_usec_t cur_time = get_time_usec();
next_loop += USECS_PER_SEC * interval;
@ -744,6 +732,5 @@ int main(int argc, char *argv[])
}
endwin();
return EXIT_SUCCESS;
}