From b3e1d6dbd5497d6ae4729df2c8018df435429e76 Mon Sep 17 00:00:00 2001 From: Rob Landley Date: Tue, 30 Oct 2018 19:38:36 -0500 Subject: Promote watch to other. --- toys/other/watch.c | 186 +++++++++++++++++++++++++++++++++++++++++++++++++++ toys/pending/watch.c | 186 --------------------------------------------------- 2 files changed, 186 insertions(+), 186 deletions(-) create mode 100644 toys/other/watch.c delete mode 100644 toys/pending/watch.c diff --git a/toys/other/watch.c b/toys/other/watch.c new file mode 100644 index 00000000..ab51148c --- /dev/null +++ b/toys/other/watch.c @@ -0,0 +1,186 @@ +/* watch.c - Execute a program periodically + * + * Copyright 2013 Sandeep Sharma + * Copyright 2013 Kyungwan Han + * + * No standard. See http://man7.org/linux/man-pages/man1/watch.1.html + * + * TODO: trailing combining characters +USE_WATCH(NEWTOY(watch, "^<1n%<100=2000tebx", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_LOCALE)) + +config WATCH + bool "watch" + default y + help + usage: watch [-teb] [-n SEC] PROG ARGS + + Run PROG every -n seconds, showing output. Hit q to quit. + + -n Loop period in seconds (default 2) + -t Don't print header + -e Exit on error + -b Beep on command error + -x Exec command directly (vs "sh -c") +*/ + +#define FOR_watch +#include "toys.h" + +GLOBALS( + int n; + + pid_t pid, oldpid; +) + +// When a child process exits, stop tracking them. Handle errors for -be +void watch_child(int sig) +{ + int status; + pid_t pid = wait(&status); + + status = WIFEXITED(status) ? WEXITSTATUS(status) : WTERMSIG(status)+127; + if (status) { + // TODO should this be beep()? + if (toys.optflags&FLAG_b) putchar('\b'); + if (toys.optflags&FLAG_e) { + printf("Exit status %d\r\n", status); + tty_reset(); + _exit(status); + } + } + + if (pid == TT.oldpid) TT.oldpid = 0; + else if (pid == TT.pid) TT.pid = 0; +} + +// Return early for low-ascii characters with special behavior, +// discard remaining low ascii, escape other unprintable chars normally +int watch_escape(FILE *out, int cols, int wc) +{ + if (wc==27 || (wc>=7 && wc<=13)) return -1; + if (wc < 32) return 0; + + return crunch_escape(out, cols, wc); +} + +void watch_main(void) +{ + char *cmdv[] = {"/bin/sh", "-c", 0, 0}, *cmd, *ss; + long long now, then = millitime(); + unsigned width, height, i, cmdlen, len, xx = xx, yy = yy, active = active; + struct pollfd pfd[2]; + pid_t pid = 0; + int fds[2], cc; + + // Assemble header line in cmd, cmdlen, and cmdv + for (i = TT.n%1000, len = i ? 3 : 1; i && !(i%10); i /= 10) len--; + len = sprintf(toybuf, "Every %u.%0*us:", TT.n/1000, len, i)+1; + cmdlen = len; + for (i = 0; toys.optargs[i]; i++) len += strlen(toys.optargs[i])+1; + ss = stpcpy(cmd = xmalloc(len), toybuf); + cmdv[2] = cmd+cmdlen; + for (i = 0; toys.optargs[i]; i++) ss += sprintf(ss, " %s",toys.optargs[i]); + cmdlen = ss-cmd; + + // Need to poll on process output and stdin + memset(pfd, 0, sizeof(pfd)); + pfd[0].events = pfd[1].events = POLLIN; + + xsignal_flags(SIGCHLD, watch_child, SA_RESTART|SA_NOCLDSTOP); + + for (;;) { + + // Time for a new period? + if ((now = millitime())>=then) { + + // Incrementing then instead of adding offset to now avoids drift, + // loop is in case we got suspend/resumed and need to skip periods + while ((then += TT.n)<=now); + start_redraw(&width, &height); + + // redraw the header + if (!(toys.optflags&FLAG_t)) { + time_t t = time(0); + int pad, ctimelen; + + // Get and measure time string, trimming gratuitous \n + ctimelen = strlen(ss = ctime(&t)); + if (ss[ctimelen-1]=='\n') ss[--ctimelen] = 0; + + // print cmdline, then * or ' ' (showing truncation), then ctime + pad = width-++ctimelen; + if (pad>0) draw_trim(cmd, -pad, pad); + printf("%c", padctimelen ? 0 : width-1)); + if (yy>=3) xprintf("\r\n"); + xx = 0; + yy = 2; + } + + // If child didn't exit, send TERM signal to current and KILL to previous + if (TT.oldpid>0) kill(TT.oldpid, SIGKILL); + if (TT.pid>0) kill(TT.pid, SIGTERM); + TT.oldpid = pid; + if (fds[0]>0) close(fds[0]); + if (fds[1]>0) close(fds[1]); + + // Spawn child process + memset(fds, 0, sizeof(fds)); + TT.pid = xpopen_both((toys.optflags&FLAG_x) ? toys.optargs : cmdv, fds); + pfd[1].fd = fds[1]; + active = 1; + } + + // Fetch data from child process or keyboard, with timeout + len = 0; + xpoll(pfd, 1+(active && yy=height) break; + } + xx += crunch_str(&ss, width-xx, stdout, 0, watch_escape); + if (xx==width) { + xx = 0; + if (++yy>=height) break; + continue; + } + + if (ss-toybuf==len || *ss>27) break; + cc = *ss++; + if (cc==27) continue; // TODO + + // Handle BEL BS HT LF VT FF CR + if (cc>=10 && cc<=12) { + if (++yy>=height) break; + if (cc=='\n') putchar('\r'), xx = 0; + } + putchar(cc); + if (cc=='\b' && xx) xx--; + else if (cc=='\t') { + xx = (xx|7)+1; + if (xx>width-1) xx = width-1; + } + } + } + + if (CFG_TOYBOX_FREE) free(cmd); +} diff --git a/toys/pending/watch.c b/toys/pending/watch.c deleted file mode 100644 index 42dc25c2..00000000 --- a/toys/pending/watch.c +++ /dev/null @@ -1,186 +0,0 @@ -/* watch.c - Execute a program periodically - * - * Copyright 2013 Sandeep Sharma - * Copyright 2013 Kyungwan Han - * - * No standard. See http://man7.org/linux/man-pages/man1/watch.1.html - * - * TODO: add -USE_WATCH(NEWTOY(watch, "^<1n%<100=2000tebx", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_LOCALE)) - -config WATCH - bool "watch" - default n - help - usage: watch [-teb] [-n SEC] PROG ARGS - - Run PROG every -n seconds, showing output. Hit q to quit. - - -n Loop period in seconds (default 2) - -t Don't print header - -e Exit on error - -b Beep on command error - -x Exec command directly (vs "sh -c") -*/ - -#define FOR_watch -#include "toys.h" - -GLOBALS( - int n; - - pid_t pid, oldpid; -) - -// When a child process exits, stop tracking them. Handle errors for -be -void watch_child(int sig) -{ - int status; - pid_t pid = wait(&status); - - status = WIFEXITED(status) ? WEXITSTATUS(status) : WTERMSIG(status)+127; - if (status) { - // TODO should this be beep()? - if (toys.optflags&FLAG_b) putchar('\b'); - if (toys.optflags&FLAG_e) { - printf("Exit status %d\r\n", status); - tty_reset(); - _exit(status); - } - } - - if (pid == TT.oldpid) TT.oldpid = 0; - else if (pid == TT.pid) TT.pid = 0; -} - -// Return early for low-ascii characters with special behavior, -// discard remaining low ascii, escape other unprintable chars normally -int watch_escape(FILE *out, int cols, int wc) -{ - if (wc==27 || (wc>=7 && wc<=13)) return -1; - if (wc < 32) return 0; - - return crunch_escape(out, cols, wc); -} - -void watch_main(void) -{ - char *cmdv[] = {"/bin/sh", "-c", 0, 0}, *cmd, *ss; - long long now, then = millitime(); - unsigned width, height, i, cmdlen, len, xx = xx, yy = yy, active = active; - struct pollfd pfd[2]; - pid_t pid = 0; - int fds[2], cc; - - // Assemble header line in cmd, cmdlen, and cmdv - for (i = TT.n%1000, len = i ? 3 : 1; i && !(i%10); i /= 10) len--; - len = sprintf(toybuf, "Every %u.%0*us:", TT.n/1000, len, i)+1; - cmdlen = len; - for (i = 0; toys.optargs[i]; i++) len += strlen(toys.optargs[i])+1; - ss = stpcpy(cmd = xmalloc(len), toybuf); - cmdv[2] = cmd+cmdlen; - for (i = 0; toys.optargs[i]; i++) ss += sprintf(ss, " %s",toys.optargs[i]); - cmdlen = ss-cmd; - - // Need to poll on process output and stdin - memset(pfd, 0, sizeof(pfd)); - pfd[0].events = pfd[1].events = POLLIN; - - xsignal_flags(SIGCHLD, watch_child, SA_RESTART|SA_NOCLDSTOP); - - for (;;) { - - // Time for a new period? - if ((now = millitime())>=then) { - - // Incrementing then instead of adding offset to now avoids drift, - // loop is in case we got suspend/resumed and need to skip periods - while ((then += TT.n)<=now); - start_redraw(&width, &height); - - // redraw the header - if (!(toys.optflags&FLAG_t)) { - time_t t = time(0); - int pad, ctimelen; - - // Get and measure time string, trimming gratuitous \n - ctimelen = strlen(ss = ctime(&t)); - if (ss[ctimelen-1]=='\n') ss[--ctimelen] = 0; - - // print cmdline, then * or ' ' (showing truncation), then ctime - pad = width-++ctimelen; - if (pad>0) draw_trim(cmd, -pad, pad); - printf("%c", padctimelen ? 0 : width-1)); - if (yy>=3) xprintf("\r\n"); - xx = 0; - yy = 2; - } - - // If child didn't exit, send TERM signal to current and KILL to previous - if (TT.oldpid>0) kill(TT.oldpid, SIGKILL); - if (TT.pid>0) kill(TT.pid, SIGTERM); - TT.oldpid = pid; - if (fds[0]>0) close(fds[0]); - if (fds[1]>0) close(fds[1]); - - // Spawn child process - memset(fds, 0, sizeof(fds)); - TT.pid = xpopen_both((toys.optflags&FLAG_x) ? toys.optargs : cmdv, fds); - pfd[1].fd = fds[1]; - active = 1; - } - - // Fetch data from child process or keyboard, with timeout - len = 0; - xpoll(pfd, 1+(active && yy=height) break; - } - xx += crunch_str(&ss, width-xx, stdout, 0, watch_escape); - if (xx==width) { - xx = 0; - if (++yy>=height) break; - continue; - } - - if (ss-toybuf==len || *ss>27) break; - cc = *ss++; - if (cc==27) continue; // TODO - - // Handle BEL BS HT LF VT FF CR - if (cc>=10 && cc<=12) { - if (++yy>=height) break; - if (cc=='\n') putchar('\r'), xx = 0; - } - putchar(cc); - if (cc=='\b' && xx) xx--; - else if (cc=='\t') { - xx = (xx|7)+1; - if (xx>width-1) xx = width-1; - } - } - } - - if (CFG_TOYBOX_FREE) free(cmd); -} -- cgit v1.2.3