1 /* watch -- execute a program repeatedly, displaying output fullscreen
3 * Based on the original 1991 'watch' by Tony Rems <rembo@unisoft.com>
4 * (with mods and corrections by Francois Pinard).
6 * Substantially reworked, new features (differences option, SIGWINCH
7 * handling, unlimited command length, long line handling) added Apr 1999 by
8 * Mike Coleman <mkc@acm.org>.
10 * Changes by Albert Cahalan, 2002-2003.
13 #define VERSION "0.2.0"
22 #include <sys/ioctl.h>
26 /* #include "proc/procps.h" */
28 static struct option longopts
[] = {
29 {"differences", optional_argument
, 0, 'd'},
30 {"help", no_argument
, 0, 'h'},
31 {"interval", required_argument
, 0, 'n'},
32 {"no-title", no_argument
, 0, 't'},
33 {"version", no_argument
, 0, 'v'},
38 "Usage: %s [-dhntv] [--differences[=cumulative]] [--help] [--interval=<n>] [--no-title] [--version] <command>\n";
40 static char *progname
;
42 static int curses_started
= 0;
43 static int height
= 24, width
= 80;
44 static int screen_size_changed
= 0;
45 static int first_screen
= 1;
46 static int show_title
= 2; // number of lines used, 2 or 0
48 #define min(x,y) ((x) > (y) ? (y) : (x))
50 //static void do_usage(void) NORETURN;
51 static void do_usage(void)
53 fprintf(stderr
, usage
, progname
);
57 //static void do_exit(int status) NORETURN;
58 static void do_exit(int status
)
66 //static void die(int notused) NORETURN;
67 static void die(int notused
)
74 winch_handler(int notused
)
77 screen_size_changed
= 1;
81 get_terminal_size(void)
84 if (ioctl(2, TIOCGWINSZ
, &w
) == 0) {
93 main(int argc
, char *argv
[])
96 int option_differences
= 0,
97 option_differences_cumulative
= 0,
98 option_help
= 0, option_version
= 0;
101 int command_length
= 0; /* not including final \0 */
103 setlocale(LC_ALL
, "");
106 while ((optc
= getopt_long(argc
, argv
, "+d::hn:vt", longopts
, (int *) 0))
110 option_differences
= 1;
112 option_differences_cumulative
= 1;
123 interval
= strtol(optarg
, &str
, 10);
124 if (!*optarg
|| *str
)
137 if (option_version
) {
138 fprintf(stderr
, "%s\n", VERSION
);
144 fprintf(stderr
, usage
, progname
);
145 fputs(" -d, --differences[=cumulative]\thighlight changes between updates\n", stderr
);
146 fputs("\t\t(cumulative means highlighting is cumulative)\n", stderr
);
147 fputs(" -h, --help\t\t\t\tprint a summary of the options\n", stderr
);
148 fputs(" -n, --interval=<seconds>\t\tseconds to wait between updates\n", stderr
);
149 fputs(" -v, --version\t\t\t\tprint the version number\n", stderr
);
150 fputs(" -t, --no-title\t\t\tturns off showing the header\n", stderr
);
157 command
= strdup(argv
[optind
++]);
158 command_length
= strlen(command
);
159 for (; optind
< argc
; optind
++) {
161 int s
= strlen(argv
[optind
]);
162 command
= realloc(command
, command_length
+ s
+ 2); /* space and \0 */
163 endp
= command
+ command_length
;
165 memcpy(endp
+ 1, argv
[optind
], s
);
166 command_length
+= 1 + s
; /* space then string length */
167 command
[command_length
] = '\0';
172 /* Catch keyboard interrupts so we can put tty back in a sane state. */
174 signal(SIGTERM
, die
);
176 signal(SIGWINCH
, winch_handler
);
178 /* Set up tty for curses use. */
186 time_t t
= time(NULL
);
187 char *ts
= ctime(&t
);
188 int tsl
= strlen(ts
);
194 if (screen_size_changed
) {
196 resizeterm(height
, width
);
198 /* redrawwin(stdscr); */
199 screen_size_changed
= 0;
204 // left justify interval and command,
205 // right justify time, clipping all to fit window width
206 asprintf(&header
, "Every %ds: %.*s",
207 interval
, min(width
- 1, command_length
), command
);
208 mvaddstr(0, 0, header
);
209 if (strlen(header
) > (size_t) (width
- tsl
- 1))
210 mvaddstr(0, width
- tsl
- 4, "... ");
211 mvaddstr(0, width
- tsl
+ 1, ts
);
215 if (!(p
= popen(command
, "r"))) {
220 for (y
= show_title
; y
< height
; y
++) {
221 int eolseen
= 0, tabpending
= 0;
222 for (x
= 0; x
< width
; x
++) {
227 /* if there is a tab pending, just spit spaces until the
228 next stop instead of reading characters */
232 while (c
!= EOF
&& !isprint(c
)
236 if (!oldeolseen
&& x
== 0) {
243 if (c
== EOF
|| c
== '\n' || c
== '\t')
245 if (tabpending
&& (((x
+ 1) % 8) == 0))
249 if (option_differences
) {
251 char oldc
= oldch
& A_CHARTEXT
;
255 (option_differences_cumulative
256 && (oldch
& A_ATTRIBUTES
)));
264 oldeolseen
= eolseen
;