2011-06-05 18:35:47 +05:30
|
|
|
|
/*
|
|
|
|
|
* watch -- execute a program repeatedly, displaying output fullscreen
|
2002-02-02 04:17:29 +05:30
|
|
|
|
*
|
|
|
|
|
* Based on the original 1991 'watch' by Tony Rems <rembo@unisoft.com>
|
|
|
|
|
* (with mods and corrections by Francois Pinard).
|
|
|
|
|
*
|
|
|
|
|
* Substantially reworked, new features (differences option, SIGWINCH
|
2011-06-05 18:35:47 +05:30
|
|
|
|
* handling, unlimited command length, long line handling) added Apr
|
|
|
|
|
* 1999 by Mike Coleman <mkc@acm.org>.
|
2002-12-15 06:00:17 +05:30
|
|
|
|
*
|
2003-03-18 05:12:00 +05:30
|
|
|
|
* Changes by Albert Cahalan, 2002-2003.
|
2009-11-24 05:30:43 +05:30
|
|
|
|
* stderr handling, exec, and beep option added by Morty Abzug, 2008
|
2009-11-04 00:54:27 +05:30
|
|
|
|
* Unicode Support added by Jarrod Lowe <procps@rrod.net> in 2009.
|
2012-03-02 17:59:36 +05:30
|
|
|
|
*
|
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
|
|
|
*
|
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
|
*
|
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
|
|
|
* License along with this library; if not, write to the Free Software
|
|
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
2002-02-02 04:17:29 +05:30
|
|
|
|
*/
|
|
|
|
|
|
2011-10-09 16:42:04 +05:30
|
|
|
|
#include "c.h"
|
2011-12-20 16:42:37 +05:30
|
|
|
|
#include "config.h"
|
2012-03-23 18:02:24 +05:30
|
|
|
|
#include "fileutils.h"
|
2011-10-09 16:42:04 +05:30
|
|
|
|
#include "nls.h"
|
2012-01-04 23:53:19 +05:30
|
|
|
|
#include "strutils.h"
|
2011-10-10 00:59:26 +05:30
|
|
|
|
#include "xalloc.h"
|
2002-02-02 04:17:29 +05:30
|
|
|
|
#include <ctype.h>
|
2011-06-05 18:35:47 +05:30
|
|
|
|
#include <errno.h>
|
2002-02-02 04:17:29 +05:30
|
|
|
|
#include <getopt.h>
|
2011-06-05 18:35:47 +05:30
|
|
|
|
#include <locale.h>
|
2013-08-25 13:13:20 +05:30
|
|
|
|
#include <limits.h>
|
2002-02-02 04:17:29 +05:30
|
|
|
|
#include <signal.h>
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <sys/ioctl.h>
|
2009-11-24 05:30:46 +05:30
|
|
|
|
#include <sys/time.h>
|
2012-01-24 11:06:15 +05:30
|
|
|
|
#include <sys/wait.h>
|
2011-06-05 18:35:47 +05:30
|
|
|
|
#include <termios.h>
|
2002-02-02 04:17:29 +05:30
|
|
|
|
#include <time.h>
|
|
|
|
|
#include <unistd.h>
|
2011-12-20 16:42:37 +05:30
|
|
|
|
#ifdef WITH_WATCH8BIT
|
2015-07-06 01:07:48 +05:30
|
|
|
|
# define _XOPEN_SOURCE_EXTENDED 1
|
2011-10-09 16:42:04 +05:30
|
|
|
|
# include <wchar.h>
|
2012-05-30 01:09:57 +05:30
|
|
|
|
# include <wctype.h>
|
2011-10-09 16:42:04 +05:30
|
|
|
|
# include <ncursesw/ncurses.h>
|
2011-06-05 18:35:47 +05:30
|
|
|
|
#else
|
2011-10-09 16:42:04 +05:30
|
|
|
|
# include <ncurses.h>
|
2011-06-05 18:35:47 +05:30
|
|
|
|
#endif /* WITH_WATCH8BIT */
|
2002-02-02 04:17:29 +05:30
|
|
|
|
|
2004-08-27 19:53:36 +05:30
|
|
|
|
#ifdef FORCE_8BIT
|
2011-10-09 16:42:04 +05:30
|
|
|
|
# undef isprint
|
|
|
|
|
# define isprint(x) ( (x>=' '&&x<='~') || (x>=0xa0) )
|
2004-08-27 19:53:36 +05:30
|
|
|
|
#endif
|
|
|
|
|
|
2012-03-10 17:59:34 +05:30
|
|
|
|
/* 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)
|
2022-04-01 01:06:57 +05:30
|
|
|
|
#define WATCH_EQUEXIT (1 << 8)
|
2023-01-17 15:15:48 +05:30
|
|
|
|
#define WATCH_NORERUN (1 << 9)
|
2012-03-10 17:59:34 +05:30
|
|
|
|
|
2002-02-02 04:17:29 +05:30
|
|
|
|
static int curses_started = 0;
|
2012-03-09 03:11:23 +05:30
|
|
|
|
static long height = 24, width = 80;
|
2002-11-29 04:39:48 +05:30
|
|
|
|
static int screen_size_changed = 0;
|
|
|
|
|
static int first_screen = 1;
|
2011-06-05 18:35:47 +05:30
|
|
|
|
static int show_title = 2; /* number of lines used, 2 or 0 */
|
2009-11-24 05:30:46 +05:30
|
|
|
|
static int precise_timekeeping = 0;
|
2020-10-19 16:33:44 +05:30
|
|
|
|
static int line_wrap = 1;
|
2002-02-02 04:17:29 +05:30
|
|
|
|
|
|
|
|
|
#define min(x,y) ((x) > (y) ? (y) : (x))
|
2014-08-20 22:44:13 +05:30
|
|
|
|
#define MAX_ANSIBUF 100
|
2010-03-01 11:47:11 +05:30
|
|
|
|
|
2011-06-05 18:35:47 +05:30
|
|
|
|
static void __attribute__ ((__noreturn__))
|
|
|
|
|
usage(FILE * out)
|
2010-03-01 11:47:11 +05:30
|
|
|
|
{
|
2011-10-09 16:42:04 +05:30
|
|
|
|
fputs(USAGE_HEADER, out);
|
2011-06-05 18:35:47 +05:30
|
|
|
|
fprintf(out,
|
2011-12-17 23:02:47 +05:30
|
|
|
|
_(" %s [options] command\n"), program_invocation_short_name);
|
2011-10-09 16:42:04 +05:30
|
|
|
|
fputs(USAGE_OPTIONS, out);
|
2013-12-28 03:55:39 +05:30
|
|
|
|
fputs(_(" -b, --beep beep if command has a non-zero exit\n"), out);
|
2014-09-06 14:16:27 +05:30
|
|
|
|
fputs(_(" -c, --color interpret ANSI color and style sequences\n"), out);
|
2013-12-28 03:55:39 +05:30
|
|
|
|
fputs(_(" -d, --differences[=<permanent>]\n"
|
|
|
|
|
" highlight changes between updates\n"), out);
|
|
|
|
|
fputs(_(" -e, --errexit exit if command has a non-zero exit\n"), out);
|
|
|
|
|
fputs(_(" -g, --chgexit exit when output from command changes\n"), out);
|
2022-04-01 01:06:57 +05:30
|
|
|
|
fputs(_(" -q, --equexit <cycles>\n"
|
|
|
|
|
" exit when output from command does not change\n"), out);
|
2013-12-28 03:55:39 +05:30
|
|
|
|
fputs(_(" -n, --interval <secs> seconds to wait between updates\n"), out);
|
|
|
|
|
fputs(_(" -p, --precise attempt run command in precise intervals\n"), out);
|
2023-01-17 15:15:48 +05:30
|
|
|
|
fputs(_(" -r, --no-rerun do not rerun program on window resize\n"), out);
|
2013-12-28 03:55:39 +05:30
|
|
|
|
fputs(_(" -t, --no-title turn off header\n"), out);
|
2020-10-19 16:33:44 +05:30
|
|
|
|
fputs(_(" -w, --no-wrap turn off line wrapping\n"), out);
|
2013-12-28 03:55:39 +05:30
|
|
|
|
fputs(_(" -x, --exec pass command to exec instead of \"sh -c\"\n"), out);
|
2011-10-09 16:42:04 +05:30
|
|
|
|
fputs(USAGE_SEPARATOR, out);
|
|
|
|
|
fputs(USAGE_HELP, out);
|
|
|
|
|
fputs(_(" -v, --version output version information and exit\n"), out);
|
|
|
|
|
fprintf(out, USAGE_MAN_TAIL("watch(1)"));
|
2011-06-05 18:35:47 +05:30
|
|
|
|
|
|
|
|
|
exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
|
2010-03-01 11:47:11 +05:30
|
|
|
|
}
|
|
|
|
|
|
2014-09-06 14:16:27 +05:30
|
|
|
|
static int nr_of_colors;
|
|
|
|
|
static int attributes;
|
|
|
|
|
static int fg_col;
|
|
|
|
|
static int bg_col;
|
2020-07-13 07:38:26 +05:30
|
|
|
|
static int more_colors;
|
2014-09-06 14:16:27 +05:30
|
|
|
|
|
2014-09-08 19:20:24 +05:30
|
|
|
|
|
|
|
|
|
static void reset_ansi(void)
|
|
|
|
|
{
|
|
|
|
|
attributes = A_NORMAL;
|
|
|
|
|
fg_col = 0;
|
|
|
|
|
bg_col = 0;
|
|
|
|
|
}
|
|
|
|
|
|
2011-06-05 18:35:47 +05:30
|
|
|
|
static void init_ansi_colors(void)
|
2010-03-01 11:47:11 +05:30
|
|
|
|
{
|
2011-06-05 18:35:47 +05:30
|
|
|
|
short ncurses_colors[] = {
|
2014-09-08 19:20:24 +05:30
|
|
|
|
-1, COLOR_BLACK, COLOR_RED, COLOR_GREEN, COLOR_YELLOW,
|
|
|
|
|
COLOR_BLUE, COLOR_MAGENTA, COLOR_CYAN, COLOR_WHITE
|
2011-06-05 18:35:47 +05:30
|
|
|
|
};
|
2014-09-06 14:16:27 +05:30
|
|
|
|
nr_of_colors = sizeof(ncurses_colors) / sizeof(short);
|
|
|
|
|
|
2020-07-13 07:38:26 +05:30
|
|
|
|
more_colors = (COLORS >= 16) && (COLOR_PAIRS >= 16 * 16);
|
|
|
|
|
|
|
|
|
|
// Initialize ncurses colors. -1 is terminal default
|
|
|
|
|
// 0-7 are auto created standard colors initialized by ncurses
|
|
|
|
|
if (more_colors) {
|
|
|
|
|
// Initialize using ANSI SGR 8-bit specified colors
|
|
|
|
|
// 8-15 are bright colors
|
|
|
|
|
init_color(8, 333, 333, 333); // Bright black
|
|
|
|
|
init_color(9, 1000, 333, 333); // Bright red
|
|
|
|
|
init_color(10, 333, 1000, 333); // Bright green
|
|
|
|
|
init_color(11, 1000, 1000, 333); // Bright yellow
|
|
|
|
|
init_color(12, 333, 333, 1000); // Bright blue
|
|
|
|
|
init_color(13, 1000, 333, 1000); // Bright magenta
|
|
|
|
|
init_color(14, 333, 1000, 1000); // Bright cyan
|
|
|
|
|
// Often ncurses is built with only 256 colors, so lets
|
|
|
|
|
// stop here - so we can support the -1 terminal default
|
|
|
|
|
//init_color(15, 1000, 1000, 1000); // Bright white
|
|
|
|
|
nr_of_colors += 7;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Initialize all color pairs with ncurses
|
2014-09-06 14:16:27 +05:30
|
|
|
|
for (bg_col = 0; bg_col < nr_of_colors; bg_col++)
|
|
|
|
|
for (fg_col = 0; fg_col < nr_of_colors; fg_col++)
|
2020-07-13 07:38:26 +05:30
|
|
|
|
init_pair(bg_col * nr_of_colors + fg_col + 1, fg_col - 1, bg_col - 1);
|
|
|
|
|
|
2014-09-08 19:20:24 +05:30
|
|
|
|
reset_ansi();
|
2010-03-01 11:47:11 +05:30
|
|
|
|
}
|
|
|
|
|
|
2014-09-06 14:16:27 +05:30
|
|
|
|
|
2020-07-13 06:29:29 +05:30
|
|
|
|
static int process_ansi_color_escape_sequence(char** escape_sequence) {
|
2020-07-13 07:38:26 +05:30
|
|
|
|
// process SGR ANSI color escape sequence
|
|
|
|
|
// Eg 8-bit
|
|
|
|
|
// 38;5;⟨n⟩ (set fg color to n)
|
|
|
|
|
// 48;5;⟨n⟩ (set bg color to n)
|
|
|
|
|
//
|
|
|
|
|
// Eg 24-bit (not yet implemented)
|
|
|
|
|
// ESC[ 38;2;⟨r⟩;⟨g⟩;⟨b⟩ m Select RGB foreground color
|
|
|
|
|
// ESC[ 48;2;⟨r⟩;⟨g⟩;⟨b⟩ m Select RGB background color
|
|
|
|
|
int num;
|
2020-07-02 13:15:29 +05:30
|
|
|
|
|
2021-05-06 20:00:54 +05:30
|
|
|
|
if (!escape_sequence)
|
|
|
|
|
return 0; /* avoid NULLPTR dereference, return "not understood" */
|
|
|
|
|
|
2020-07-13 07:38:26 +05:30
|
|
|
|
if ((*escape_sequence)[0] != ';')
|
|
|
|
|
return 0; /* not understood */
|
2020-07-02 13:15:29 +05:30
|
|
|
|
|
2020-07-13 07:38:26 +05:30
|
|
|
|
if ((*escape_sequence)[1] == '5') {
|
|
|
|
|
// 8 bit! ANSI specifies a predefined set of 256 colors here.
|
|
|
|
|
if ((*escape_sequence)[2] != ';')
|
|
|
|
|
return 0; /* not understood */
|
|
|
|
|
num = strtol((*escape_sequence) + 3, escape_sequence, 10);
|
|
|
|
|
if (num >= 0 && num <= 7) {
|
|
|
|
|
// 0-7 are standard colors same as SGR 30-37
|
|
|
|
|
return num + 1;
|
|
|
|
|
}
|
|
|
|
|
if (num >= 8 && num <= 15) {
|
|
|
|
|
// 8-15 are standard colors same as SGR 90-97
|
|
|
|
|
return more_colors ? num + 1 : num - 8 + 1;
|
|
|
|
|
}
|
2020-07-13 06:29:29 +05:30
|
|
|
|
|
2020-07-13 07:38:26 +05:30
|
|
|
|
// Remainder aren't yet implemented
|
|
|
|
|
// 16-231: 6 × 6 × 6 cube (216 colors): 16 + 36 × r + 6 × g + b (0 ≤ r, g, b ≤ 5)
|
|
|
|
|
// 232-255: grayscale from black to white in 24 steps
|
|
|
|
|
}
|
2020-07-02 13:15:29 +05:30
|
|
|
|
|
2020-07-13 07:38:26 +05:30
|
|
|
|
return 0; /* not understood */
|
2020-07-02 13:15:29 +05:30
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int set_ansi_attribute(const int attrib, char** escape_sequence)
|
2010-03-01 11:47:11 +05:30
|
|
|
|
{
|
2011-06-05 18:35:47 +05:30
|
|
|
|
switch (attrib) {
|
2014-09-06 14:16:27 +05:30
|
|
|
|
case -1: /* restore last settings */
|
|
|
|
|
break;
|
|
|
|
|
case 0: /* restore default settings */
|
2014-09-08 19:20:24 +05:30
|
|
|
|
reset_ansi();
|
2014-09-06 14:16:27 +05:30
|
|
|
|
break;
|
|
|
|
|
case 1: /* set bold / increased intensity */
|
|
|
|
|
attributes |= A_BOLD;
|
|
|
|
|
break;
|
|
|
|
|
case 2: /* set decreased intensity (if supported) */
|
|
|
|
|
attributes |= A_DIM;
|
|
|
|
|
break;
|
|
|
|
|
#ifdef A_ITALIC
|
|
|
|
|
case 3: /* set italic (if supported) */
|
|
|
|
|
attributes |= A_ITALIC;
|
|
|
|
|
break;
|
|
|
|
|
#endif
|
|
|
|
|
case 4: /* set underline */
|
|
|
|
|
attributes |= A_UNDERLINE;
|
|
|
|
|
break;
|
|
|
|
|
case 5: /* set blinking */
|
|
|
|
|
attributes |= A_BLINK;
|
|
|
|
|
break;
|
|
|
|
|
case 7: /* set inversed */
|
|
|
|
|
attributes |= A_REVERSE;
|
|
|
|
|
break;
|
|
|
|
|
case 21: /* unset bold / increased intensity */
|
|
|
|
|
attributes &= ~A_BOLD;
|
|
|
|
|
break;
|
|
|
|
|
case 22: /* unset bold / any intensity modifier */
|
|
|
|
|
attributes &= ~(A_BOLD | A_DIM);
|
|
|
|
|
break;
|
|
|
|
|
#ifdef A_ITALIC
|
|
|
|
|
case 23: /* unset italic */
|
2014-09-06 14:24:34 +05:30
|
|
|
|
attributes &= ~A_ITALIC;
|
2014-09-06 14:16:27 +05:30
|
|
|
|
break;
|
|
|
|
|
#endif
|
|
|
|
|
case 24: /* unset underline */
|
|
|
|
|
attributes &= ~A_UNDERLINE;
|
|
|
|
|
break;
|
|
|
|
|
case 25: /* unset blinking */
|
|
|
|
|
attributes &= ~A_BLINK;
|
|
|
|
|
break;
|
|
|
|
|
case 27: /* unset inversed */
|
|
|
|
|
attributes &= ~A_REVERSE;
|
|
|
|
|
break;
|
2020-07-13 06:29:29 +05:30
|
|
|
|
case 38:
|
|
|
|
|
fg_col = process_ansi_color_escape_sequence(escape_sequence);
|
|
|
|
|
if (fg_col == 0) {
|
|
|
|
|
return 0; /* not understood */
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case 39:
|
|
|
|
|
fg_col = 0;
|
|
|
|
|
break;
|
|
|
|
|
case 48:
|
|
|
|
|
bg_col = process_ansi_color_escape_sequence(escape_sequence);
|
|
|
|
|
if (bg_col == 0) {
|
|
|
|
|
return 0; /* not understood */
|
|
|
|
|
}
|
2017-12-20 16:39:41 +05:30
|
|
|
|
break;
|
|
|
|
|
case 49:
|
|
|
|
|
bg_col = 0;
|
|
|
|
|
break;
|
2014-09-06 14:16:27 +05:30
|
|
|
|
default:
|
|
|
|
|
if (attrib >= 30 && attrib <= 37) { /* set foreground color */
|
2014-09-08 19:20:24 +05:30
|
|
|
|
fg_col = attrib - 30 + 1;
|
2014-09-06 14:16:27 +05:30
|
|
|
|
} else if (attrib >= 40 && attrib <= 47) { /* set background color */
|
2014-09-08 19:20:24 +05:30
|
|
|
|
bg_col = attrib - 40 + 1;
|
2020-07-13 07:38:26 +05:30
|
|
|
|
} else if (attrib >= 90 && attrib <= 97) { /* set bright fg color */
|
|
|
|
|
fg_col = more_colors ? attrib - 90 + 9 : attrib - 90 + 1;
|
|
|
|
|
} else if (attrib >= 100 && attrib <= 107) { /* set bright bg color */
|
|
|
|
|
bg_col = more_colors ? attrib - 100 + 9 : attrib - 100 + 1;
|
2016-07-09 10:22:54 +05:30
|
|
|
|
} else {
|
|
|
|
|
return 0; /* Not understood */
|
2014-09-06 14:16:27 +05:30
|
|
|
|
}
|
2011-06-05 18:35:47 +05:30
|
|
|
|
}
|
2020-07-13 07:38:26 +05:30
|
|
|
|
attr_set(attributes, bg_col * nr_of_colors + fg_col + 1, NULL);
|
2016-07-09 11:27:11 +05:30
|
|
|
|
return 1;
|
2010-03-01 11:47:11 +05:30
|
|
|
|
}
|
2002-02-02 04:17:29 +05:30
|
|
|
|
|
2011-06-05 18:35:47 +05:30
|
|
|
|
static void process_ansi(FILE * fp)
|
2002-02-02 04:17:29 +05:30
|
|
|
|
{
|
2013-10-18 11:34:15 +05:30
|
|
|
|
int i, c;
|
2011-06-05 18:35:47 +05:30
|
|
|
|
char buf[MAX_ANSIBUF];
|
2015-09-07 10:30:00 +05:30
|
|
|
|
char *numstart, *endptr = buf;
|
2020-07-02 13:15:29 +05:30
|
|
|
|
int ansi_attribute;
|
2011-06-05 18:35:47 +05:30
|
|
|
|
|
|
|
|
|
c = getc(fp);
|
2018-04-27 18:57:17 +05:30
|
|
|
|
|
|
|
|
|
if (c == '(') {
|
|
|
|
|
c = getc(fp);
|
|
|
|
|
c = getc(fp);
|
|
|
|
|
}
|
2011-06-05 18:35:47 +05:30
|
|
|
|
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;
|
|
|
|
|
}
|
2016-07-08 12:59:59 +05:30
|
|
|
|
if ((c < '0' || c > '9') && c != ';') {
|
2011-06-05 18:35:47 +05:30
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
buf[i] = (char)c;
|
|
|
|
|
}
|
2013-10-18 11:34:15 +05:30
|
|
|
|
/*
|
|
|
|
|
* buf now contains a semicolon-separated list of decimal integers,
|
|
|
|
|
* each indicating an attribute to apply.
|
|
|
|
|
* For example, buf might contain "0;1;31", derived from the color
|
|
|
|
|
* escape sequence "<ESC>[0;1;31m". There can be 1 or more
|
|
|
|
|
* attributes to apply, but typically there are between 1 and 3.
|
|
|
|
|
*/
|
2015-02-25 23:10:53 +05:30
|
|
|
|
|
2015-11-18 17:18:09 +05:30
|
|
|
|
/* Special case of <ESC>[m */
|
|
|
|
|
if (buf[0] == '\0')
|
2020-07-02 13:15:29 +05:30
|
|
|
|
set_ansi_attribute(0, NULL);
|
2015-02-25 23:10:53 +05:30
|
|
|
|
|
2017-05-12 10:32:00 +05:30
|
|
|
|
for (endptr = numstart = buf; *endptr != '\0'; numstart = endptr + 1) {
|
2020-07-02 13:15:29 +05:30
|
|
|
|
ansi_attribute = strtol(numstart, &endptr, 10);
|
|
|
|
|
if (!set_ansi_attribute(ansi_attribute, &endptr))
|
2016-07-09 10:22:54 +05:30
|
|
|
|
break;
|
2015-09-01 16:58:07 +05:30
|
|
|
|
if (numstart == endptr)
|
2020-07-02 13:15:29 +05:30
|
|
|
|
set_ansi_attribute(0, NULL); /* [m treated as [0m */
|
2015-09-01 16:58:07 +05:30
|
|
|
|
}
|
2002-02-02 04:17:29 +05:30
|
|
|
|
}
|
|
|
|
|
|
2011-06-05 18:35:47 +05:30
|
|
|
|
static void __attribute__ ((__noreturn__)) do_exit(int status)
|
2002-11-29 04:39:48 +05:30
|
|
|
|
{
|
|
|
|
|
if (curses_started)
|
|
|
|
|
endwin();
|
|
|
|
|
exit(status);
|
2002-02-02 04:17:29 +05:30
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* signal handler */
|
2011-06-05 18:35:47 +05:30
|
|
|
|
static void die(int notused __attribute__ ((__unused__)))
|
2002-02-02 04:17:29 +05:30
|
|
|
|
{
|
2011-06-05 18:35:47 +05:30
|
|
|
|
do_exit(EXIT_SUCCESS);
|
2002-02-02 04:17:29 +05:30
|
|
|
|
}
|
|
|
|
|
|
2011-06-05 18:35:47 +05:30
|
|
|
|
static void winch_handler(int notused __attribute__ ((__unused__)))
|
2002-02-02 04:17:29 +05:30
|
|
|
|
{
|
2002-11-29 04:39:48 +05:30
|
|
|
|
screen_size_changed = 1;
|
2002-02-02 04:17:29 +05:30
|
|
|
|
}
|
|
|
|
|
|
2004-08-27 19:53:36 +05:30
|
|
|
|
static char env_col_buf[24];
|
|
|
|
|
static char env_row_buf[24];
|
|
|
|
|
static int incoming_cols;
|
|
|
|
|
static int incoming_rows;
|
|
|
|
|
|
2011-06-05 18:35:47 +05:30
|
|
|
|
static void get_terminal_size(void)
|
2002-02-02 04:17:29 +05:30
|
|
|
|
{
|
2002-11-29 04:39:48 +05:30
|
|
|
|
struct winsize w;
|
2011-06-05 18:35:47 +05:30
|
|
|
|
if (!incoming_cols) {
|
|
|
|
|
/* have we checked COLUMNS? */
|
2004-08-27 19:53:36 +05:30
|
|
|
|
const char *s = getenv("COLUMNS");
|
|
|
|
|
incoming_cols = -1;
|
2011-06-05 18:35:47 +05:30
|
|
|
|
if (s && *s) {
|
2004-08-27 19:53:36 +05:30
|
|
|
|
long t;
|
|
|
|
|
char *endptr;
|
|
|
|
|
t = strtol(s, &endptr, 0);
|
2012-03-09 03:11:23 +05:30
|
|
|
|
if (!*endptr && 0 < t)
|
|
|
|
|
incoming_cols = t;
|
2004-08-27 19:53:36 +05:30
|
|
|
|
width = incoming_cols;
|
2012-03-09 03:11:23 +05:30
|
|
|
|
snprintf(env_col_buf, sizeof env_col_buf, "COLUMNS=%ld",
|
2011-06-05 18:35:47 +05:30
|
|
|
|
width);
|
2004-08-27 19:53:36 +05:30
|
|
|
|
putenv(env_col_buf);
|
|
|
|
|
}
|
|
|
|
|
}
|
2011-06-05 18:35:47 +05:30
|
|
|
|
if (!incoming_rows) {
|
|
|
|
|
/* have we checked LINES? */
|
2004-08-27 19:53:36 +05:30
|
|
|
|
const char *s = getenv("LINES");
|
|
|
|
|
incoming_rows = -1;
|
2011-06-05 18:35:47 +05:30
|
|
|
|
if (s && *s) {
|
2004-08-27 19:53:36 +05:30
|
|
|
|
long t;
|
|
|
|
|
char *endptr;
|
|
|
|
|
t = strtol(s, &endptr, 0);
|
2012-03-09 03:11:23 +05:30
|
|
|
|
if (!*endptr && 0 < t)
|
|
|
|
|
incoming_rows = t;
|
2004-08-27 19:53:36 +05:30
|
|
|
|
height = incoming_rows;
|
2012-03-09 03:11:23 +05:30
|
|
|
|
snprintf(env_row_buf, sizeof env_row_buf, "LINES=%ld",
|
2011-06-05 18:35:47 +05:30
|
|
|
|
height);
|
2004-08-27 19:53:36 +05:30
|
|
|
|
putenv(env_row_buf);
|
|
|
|
|
}
|
|
|
|
|
}
|
2012-03-09 03:11:23 +05:30
|
|
|
|
if (ioctl(STDERR_FILENO, TIOCGWINSZ, &w) == 0) {
|
|
|
|
|
if (incoming_cols < 0 || incoming_rows < 0) {
|
2011-06-05 18:35:47 +05:30
|
|
|
|
if (incoming_rows < 0 && w.ws_row > 0) {
|
2004-08-27 19:53:36 +05:30
|
|
|
|
height = w.ws_row;
|
2011-06-05 18:35:47 +05:30
|
|
|
|
snprintf(env_row_buf, sizeof env_row_buf,
|
2012-03-09 03:11:23 +05:30
|
|
|
|
"LINES=%ld", height);
|
2004-08-27 19:53:36 +05:30
|
|
|
|
putenv(env_row_buf);
|
|
|
|
|
}
|
2011-06-05 18:35:47 +05:30
|
|
|
|
if (incoming_cols < 0 && w.ws_col > 0) {
|
2004-08-27 19:53:36 +05:30
|
|
|
|
width = w.ws_col;
|
2011-06-05 18:35:47 +05:30
|
|
|
|
snprintf(env_col_buf, sizeof env_col_buf,
|
2012-03-09 03:11:23 +05:30
|
|
|
|
"COLUMNS=%ld", width);
|
2004-08-27 19:53:36 +05:30
|
|
|
|
putenv(env_col_buf);
|
|
|
|
|
}
|
|
|
|
|
}
|
2002-11-29 04:39:48 +05:30
|
|
|
|
}
|
2002-02-02 04:17:29 +05:30
|
|
|
|
}
|
|
|
|
|
|
2009-11-24 05:30:46 +05:30
|
|
|
|
/* get current time in usec */
|
|
|
|
|
typedef unsigned long long watch_usec_t;
|
|
|
|
|
#define USECS_PER_SEC (1000000ull)
|
2012-11-02 23:20:58 +05:30
|
|
|
|
static watch_usec_t get_time_usec()
|
2011-06-05 18:35:47 +05:30
|
|
|
|
{
|
2009-11-24 05:30:46 +05:30
|
|
|
|
struct timeval now;
|
|
|
|
|
gettimeofday(&now, NULL);
|
2011-06-05 18:35:47 +05:30
|
|
|
|
return USECS_PER_SEC * now.tv_sec + now.tv_usec;
|
2009-11-24 05:30:46 +05:30
|
|
|
|
}
|
|
|
|
|
|
2011-12-20 16:42:37 +05:30
|
|
|
|
#ifdef WITH_WATCH8BIT
|
2011-06-05 18:35:47 +05:30
|
|
|
|
/* read a wide character from a popen'd stream */
|
2009-11-04 00:54:27 +05:30
|
|
|
|
#define MAX_ENC_BYTES 16
|
2011-06-05 18:35:47 +05:30
|
|
|
|
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];
|
2009-11-04 00:54:27 +05:30
|
|
|
|
int byte = 0;
|
|
|
|
|
int convert;
|
|
|
|
|
int x;
|
|
|
|
|
wchar_t rval;
|
2011-06-05 18:35:47 +05:30
|
|
|
|
while (1) {
|
2009-11-04 00:54:27 +05:30
|
|
|
|
i[byte] = getc(s);
|
2011-06-05 18:35:47 +05:30
|
|
|
|
if (i[byte] == EOF) {
|
|
|
|
|
return WEOF;
|
|
|
|
|
}
|
2009-11-04 00:54:27 +05:30
|
|
|
|
byte++;
|
|
|
|
|
errno = 0;
|
|
|
|
|
mbtowc(NULL, NULL, 0);
|
|
|
|
|
convert = mbtowc(&rval, i, byte);
|
|
|
|
|
x = errno;
|
2011-06-05 18:35:47 +05:30
|
|
|
|
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;
|
2009-11-04 00:54:27 +05:30
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2011-06-05 18:35:47 +05:30
|
|
|
|
#endif /* WITH_WATCH8BIT */
|
2009-11-04 00:54:27 +05:30
|
|
|
|
|
2012-05-20 12:38:29 +05:30
|
|
|
|
#ifdef WITH_WATCH8BIT
|
2016-07-02 11:37:56 +05:30
|
|
|
|
static void output_header(wchar_t *restrict wcommand, int wcommand_characters, double interval)
|
2012-05-20 12:38:29 +05:30
|
|
|
|
#else
|
2012-11-02 23:20:58 +05:30
|
|
|
|
static void output_header(char *restrict command, double interval)
|
2012-05-20 12:38:29 +05:30
|
|
|
|
#endif /* WITH_WATCH8BIT */
|
2012-03-10 17:59:34 +05:30
|
|
|
|
{
|
|
|
|
|
time_t t = time(NULL);
|
|
|
|
|
char *ts = ctime(&t);
|
|
|
|
|
char *header;
|
2016-07-02 11:15:36 +05:30
|
|
|
|
char *right_header;
|
2018-04-11 10:30:00 +05:30
|
|
|
|
int max_host_name_len = (int) sysconf(_SC_HOST_NAME_MAX);
|
|
|
|
|
char hostname[max_host_name_len + 1];
|
2016-07-02 11:37:56 +05:30
|
|
|
|
int command_columns = 0; /* not including final \0 */
|
2016-07-02 11:15:36 +05:30
|
|
|
|
|
|
|
|
|
gethostname(hostname, sizeof(hostname));
|
2012-03-10 17:59:34 +05:30
|
|
|
|
|
|
|
|
|
/*
|
2016-07-02 11:15:36 +05:30
|
|
|
|
* left justify interval and command, right justify hostname and time,
|
2012-03-10 17:59:34 +05:30
|
|
|
|
* clipping all to fit window width
|
|
|
|
|
*/
|
|
|
|
|
int hlen = asprintf(&header, _("Every %.1fs: "), interval);
|
2016-07-02 11:15:36 +05:30
|
|
|
|
int rhlen = asprintf(&right_header, _("%s: %s"), hostname, ts);
|
2012-03-10 17:59:34 +05:30
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* the rules:
|
2016-07-02 11:15:36 +05:30
|
|
|
|
* width < rhlen : print nothing
|
|
|
|
|
* width < rhlen + hlen + 1: print hostname, ts
|
|
|
|
|
* width = rhlen + hlen + 1: print header, hostname, ts
|
|
|
|
|
* width < rhlen + hlen + 4: print header, ..., hostname, ts
|
|
|
|
|
* width < rhlen + hlen + wcommand_columns: print header,
|
|
|
|
|
* truncated wcommand, ..., hostname, ts
|
|
|
|
|
* width > "": print header, wcomand, hostname, ts
|
2012-03-10 17:59:34 +05:30
|
|
|
|
* this is slightly different from how it used to be
|
|
|
|
|
*/
|
2016-07-02 11:15:36 +05:30
|
|
|
|
if (width < rhlen) {
|
2012-03-10 17:59:34 +05:30
|
|
|
|
free(header);
|
2016-07-02 11:15:36 +05:30
|
|
|
|
free(right_header);
|
2012-03-10 17:59:34 +05:30
|
|
|
|
return;
|
|
|
|
|
}
|
2016-07-02 11:15:36 +05:30
|
|
|
|
if (rhlen + hlen + 1 <= width) {
|
2012-03-10 17:59:34 +05:30
|
|
|
|
mvaddstr(0, 0, header);
|
2016-07-02 11:15:36 +05:30
|
|
|
|
if (rhlen + hlen + 2 <= width) {
|
|
|
|
|
if (width < rhlen + hlen + 4) {
|
|
|
|
|
mvaddstr(0, width - rhlen - 4, "... ");
|
2012-03-10 17:59:34 +05:30
|
|
|
|
} else {
|
|
|
|
|
#ifdef WITH_WATCH8BIT
|
2016-07-02 11:37:56 +05:30
|
|
|
|
command_columns = wcswidth(wcommand, -1);
|
|
|
|
|
if (width < rhlen + hlen + command_columns) {
|
2012-03-10 17:59:34 +05:30
|
|
|
|
/* print truncated */
|
2016-07-02 11:15:36 +05:30
|
|
|
|
int available = width - rhlen - hlen;
|
2016-07-02 11:37:56 +05:30
|
|
|
|
int in_use = command_columns;
|
2012-03-10 17:59:34 +05:30
|
|
|
|
int wcomm_len = wcommand_characters;
|
|
|
|
|
while (available - 4 < in_use) {
|
|
|
|
|
wcomm_len--;
|
|
|
|
|
in_use = wcswidth(wcommand, wcomm_len);
|
|
|
|
|
}
|
|
|
|
|
mvaddnwstr(0, hlen, wcommand, wcomm_len);
|
2016-07-02 11:15:36 +05:30
|
|
|
|
mvaddstr(0, width - rhlen - 4, "... ");
|
2012-03-10 17:59:34 +05:30
|
|
|
|
} else {
|
|
|
|
|
mvaddwstr(0, hlen, wcommand);
|
|
|
|
|
}
|
|
|
|
|
#else
|
2016-07-02 11:37:56 +05:30
|
|
|
|
command_columns = strlen(command);
|
|
|
|
|
if (width < rhlen + hlen + command_columns) {
|
|
|
|
|
/* print truncated */
|
|
|
|
|
mvaddnstr(0, hlen, command, width - rhlen - hlen - 4);
|
|
|
|
|
mvaddstr(0, width - rhlen - 4, "... ");
|
|
|
|
|
} else {
|
|
|
|
|
mvaddnstr(0, hlen, command, width - rhlen - hlen);
|
|
|
|
|
}
|
2012-03-10 17:59:34 +05:30
|
|
|
|
#endif /* WITH_WATCH8BIT */
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-07-02 11:15:36 +05:30
|
|
|
|
mvaddstr(0, width - rhlen + 1, right_header);
|
2012-03-10 17:59:34 +05:30
|
|
|
|
free(header);
|
2016-07-02 11:15:36 +05:30
|
|
|
|
free(right_header);
|
2012-03-10 17:59:34 +05:30
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-19 16:33:44 +05:30
|
|
|
|
static void find_eol(FILE *p)
|
|
|
|
|
{
|
|
|
|
|
int c;
|
|
|
|
|
#ifdef WITH_WATCH8BIT
|
|
|
|
|
do {
|
|
|
|
|
c = my_getwc(p);
|
|
|
|
|
} while (c != WEOF
|
|
|
|
|
&& c!= L'\n');
|
|
|
|
|
#else
|
|
|
|
|
do {
|
|
|
|
|
c = getc(p);
|
|
|
|
|
} while (c != EOF
|
|
|
|
|
&& c != '\n');
|
|
|
|
|
#endif /* WITH_WATCH8BIT */
|
|
|
|
|
}
|
|
|
|
|
|
2012-11-02 23:20:58 +05:30
|
|
|
|
static int run_command(char *restrict command, char **restrict command_argv)
|
2012-03-10 17:59:34 +05:30
|
|
|
|
{
|
|
|
|
|
FILE *p;
|
|
|
|
|
int x, y;
|
|
|
|
|
int oldeolseen = 1;
|
|
|
|
|
int pipefd[2];
|
|
|
|
|
pid_t child;
|
|
|
|
|
int exit_early = 0;
|
2022-04-01 01:06:57 +05:30
|
|
|
|
int buffer_size = 0;
|
|
|
|
|
int unchanged_buffer = 0;
|
2012-03-10 17:59:34 +05:30
|
|
|
|
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"));
|
|
|
|
|
}
|
2014-02-04 23:16:58 +05:30
|
|
|
|
close(pipefd[1]); /* once duped, the write fd isn't needed */
|
2012-03-10 17:59:34 +05:30
|
|
|
|
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"));
|
|
|
|
|
|
2014-09-08 19:20:24 +05:30
|
|
|
|
reset_ansi();
|
2012-03-10 17:59:34 +05:30
|
|
|
|
for (y = show_title; y < height; y++) {
|
2014-09-08 21:54:28 +05:30
|
|
|
|
int eolseen = 0, tabpending = 0, tabwaspending = 0;
|
2014-09-08 21:58:08 +05:30
|
|
|
|
if (flags & WATCH_COLOR)
|
2020-07-13 06:29:29 +05:30
|
|
|
|
set_ansi_attribute(-1, NULL);
|
2012-03-10 17:59:34 +05:30
|
|
|
|
#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;
|
|
|
|
|
|
2014-09-06 14:16:27 +05:30
|
|
|
|
if (tabwaspending && (flags & WATCH_COLOR))
|
2020-07-13 06:29:29 +05:30
|
|
|
|
set_ansi_attribute(-1, NULL);
|
2014-09-06 14:16:27 +05:30
|
|
|
|
tabwaspending = 0;
|
|
|
|
|
|
2012-03-10 17:59:34 +05:30
|
|
|
|
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;
|
|
|
|
|
}
|
2012-05-30 01:09:57 +05:30
|
|
|
|
} while (c != WEOF && !iswprint(c)
|
|
|
|
|
&& c < 128
|
2012-03-10 17:59:34 +05:30
|
|
|
|
&& wcwidth(c) == 0
|
2023-01-17 11:29:00 +05:30
|
|
|
|
&& c != L'\a'
|
2012-03-10 17:59:34 +05:30
|
|
|
|
&& c != L'\n'
|
|
|
|
|
&& c != L'\t'
|
|
|
|
|
&& (c != L'\033'
|
|
|
|
|
|| !(flags & WATCH_COLOR)));
|
|
|
|
|
#else
|
|
|
|
|
do
|
|
|
|
|
c = getc(p);
|
|
|
|
|
while (c != EOF && !isprint(c)
|
2023-01-17 11:29:00 +05:30
|
|
|
|
&& c != '\a'
|
2012-03-10 17:59:34 +05:30
|
|
|
|
&& 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;
|
2023-01-17 11:29:00 +05:30
|
|
|
|
else if (c == L'\a') {
|
|
|
|
|
beep();
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2012-03-10 17:59:34 +05:30
|
|
|
|
#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 */
|
|
|
|
|
}
|
2014-09-06 14:16:27 +05:30
|
|
|
|
if (c == WEOF || c == L'\n' || c == L'\t') {
|
2012-03-10 17:59:34 +05:30
|
|
|
|
c = L' ';
|
2014-09-06 14:16:27 +05:30
|
|
|
|
if (flags & WATCH_COLOR)
|
|
|
|
|
attrset(A_NORMAL);
|
|
|
|
|
}
|
2012-03-10 17:59:34 +05:30
|
|
|
|
#else
|
2014-09-06 14:16:27 +05:30
|
|
|
|
if (c == EOF || c == '\n' || c == '\t') {
|
2012-03-10 17:59:34 +05:30
|
|
|
|
c = ' ';
|
2014-09-06 14:16:27 +05:30
|
|
|
|
if (flags & WATCH_COLOR)
|
|
|
|
|
attrset(A_NORMAL);
|
|
|
|
|
}
|
2012-03-10 17:59:34 +05:30
|
|
|
|
#endif
|
2014-09-06 14:16:27 +05:30
|
|
|
|
if (tabpending && (((x + 1) % 8) == 0)) {
|
2012-03-10 17:59:34 +05:30
|
|
|
|
tabpending = 0;
|
2014-09-06 14:16:27 +05:30
|
|
|
|
tabwaspending = 1;
|
|
|
|
|
}
|
2012-03-10 17:59:34 +05:30
|
|
|
|
}
|
|
|
|
|
move(y, x);
|
2014-09-06 14:16:27 +05:30
|
|
|
|
|
2012-03-10 17:59:34 +05:30
|
|
|
|
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;
|
2022-04-01 01:06:57 +05:30
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
if (!first_screen && !exit_early && (flags & WATCH_EQUEXIT)) {
|
|
|
|
|
buffer_size++;
|
|
|
|
|
#ifdef WITH_WATCH8BIT
|
|
|
|
|
cchar_t oldc;
|
|
|
|
|
in_wch(&oldc);
|
|
|
|
|
if ((wchar_t) c == oldc.chars[0])
|
|
|
|
|
unchanged_buffer++;
|
|
|
|
|
#else
|
|
|
|
|
chtype oldch = inch();
|
|
|
|
|
unsigned char oldc = oldch & A_CHARTEXT;
|
|
|
|
|
if ((unsigned char)c == oldc)
|
|
|
|
|
unchanged_buffer++;
|
2012-03-10 17:59:34 +05:30
|
|
|
|
#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;
|
2020-10-19 16:33:44 +05:30
|
|
|
|
if (!line_wrap) {
|
|
|
|
|
reset_ansi();
|
|
|
|
|
if (flags & WATCH_COLOR)
|
|
|
|
|
attrset(A_NORMAL);
|
|
|
|
|
}
|
watch: Fix buggy line-deletion behaviour with --no-linewrap
This change is largely based upon Justin's patch, I just moved the
reset_ansi() parts out otherwise you get strange colour reset
behaviours.
Original patch message:
I used the --no-linewrap (-w) option for the first time today, watching
some wide output that didn't quite fit in my tmux pane. Quickly I
noticed a problem: while --no-linewrap did indeed eliminate the
spillover of lines too long for the terminal "window" width, it *also*
resulted in a bunch of lines from the program output being hidden
entirely.
After some fiddling around, the exact problematic behavior appears to be
as follows:
1. Lines which would have wrapped (more than $COLUMNS chars long) are
handled correctly.
2. Lines which would *not* have wrapped (shorter than $COLUMNS) are
printed; but then the next line is *not* printed! For long sequences
of non-wrap-length lines, you get an every-other-line-is-visible
sort of effect.
The logic underlying the problem seems to be this: in the run_command
loop, if the x loop goes all the way to completion (meaning we've
reached the right-side edge of the window area), there's a small block
of code for --no-linewrap whose main purpose is to call find_eol, which
eats input until it hits a newline (or EOF). Clearly this is intended to
be done for lines that are too long, so that the excess characters are
discarded and the input pointer is ready to go for the subsequent line.
However, this code isn't in any way conditional on the value of eolseen!
Short/wouldn't-wrap lines will have encountered a newline character
before exhausting the entire x loop, and therefore eolseen will be true.
Long/would-wrap lines will not have encountered a newline when the x
loop is exhausted, and so eolseen will be false.
Nevertheless, find_eol is called in *both* cases. For long lines, it
does what it's meant to do. For short lines, *the newline has already
been encountered and dealt with*, and so the actual effect of find_eol
is to eat the entirety of the next line, all the way through to its
newline, such that it isn't printed at all.
References:
procps-ng/procps!157
Signed-off-by: Craig Small <csmall@dropbear.xyz>
2023-01-18 11:16:52 +05:30
|
|
|
|
if (!line_wrap && !eolseen)
|
|
|
|
|
{
|
|
|
|
|
find_eol(p);
|
|
|
|
|
}
|
2012-03-10 17:59:34 +05:30
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-04-01 01:06:57 +05:30
|
|
|
|
|
|
|
|
|
if (unchanged_buffer == buffer_size && (flags & WATCH_EQUEXIT))
|
|
|
|
|
exit_early = 1;
|
|
|
|
|
|
2012-03-10 17:59:34 +05:30
|
|
|
|
first_screen = 0;
|
|
|
|
|
refresh();
|
|
|
|
|
return exit_early;
|
|
|
|
|
}
|
|
|
|
|
|
2011-06-05 18:35:47 +05:30
|
|
|
|
int main(int argc, char *argv[])
|
2002-02-02 04:17:29 +05:30
|
|
|
|
{
|
2002-11-29 04:39:48 +05:30
|
|
|
|
int optc;
|
2006-06-17 10:22:42 +05:30
|
|
|
|
double interval = 2;
|
2022-04-01 01:06:57 +05:30
|
|
|
|
int max_cycles = 1;
|
|
|
|
|
int cycle_count = 0;
|
2018-04-23 16:04:08 +05:30
|
|
|
|
char *interval_string;
|
2002-11-29 04:39:48 +05:30
|
|
|
|
char *command;
|
2009-11-24 05:30:43 +05:30
|
|
|
|
char **command_argv;
|
2002-11-29 04:39:48 +05:30
|
|
|
|
int command_length = 0; /* not including final \0 */
|
2023-01-17 15:15:48 +05:30
|
|
|
|
watch_usec_t last_run = 0;
|
2011-06-05 18:35:47 +05:30
|
|
|
|
watch_usec_t next_loop; /* next loop time in us, used for precise time
|
|
|
|
|
* keeping only */
|
2011-12-20 16:42:37 +05:30
|
|
|
|
#ifdef WITH_WATCH8BIT
|
|
|
|
|
wchar_t *wcommand = NULL;
|
2011-06-05 18:35:47 +05:30
|
|
|
|
int wcommand_characters = 0; /* not including final \0 */
|
|
|
|
|
#endif /* WITH_WATCH8BIT */
|
2011-12-20 16:42:37 +05:30
|
|
|
|
|
2011-06-05 18:35:47 +05:30
|
|
|
|
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'},
|
2012-01-26 20:12:37 +05:30
|
|
|
|
{"chgexit", no_argument, 0, 'g'},
|
2022-04-01 01:06:57 +05:30
|
|
|
|
{"equexit", required_argument, 0, 'q'},
|
2011-06-05 18:35:47 +05:30
|
|
|
|
{"exec", no_argument, 0, 'x'},
|
|
|
|
|
{"precise", no_argument, 0, 'p'},
|
2023-01-17 15:15:48 +05:30
|
|
|
|
{"no-rerun", no_argument, 0, 'r'},
|
2011-06-05 18:35:47 +05:30
|
|
|
|
{"no-title", no_argument, 0, 't'},
|
2020-10-19 16:33:44 +05:30
|
|
|
|
{"no-wrap", no_argument, 0, 'w'},
|
2011-06-05 18:35:47 +05:30
|
|
|
|
{"version", no_argument, 0, 'v'},
|
|
|
|
|
{0, 0, 0, 0}
|
|
|
|
|
};
|
|
|
|
|
|
2013-02-20 23:01:48 +05:30
|
|
|
|
#ifdef HAVE_PROGRAM_INVOCATION_NAME
|
2012-01-03 13:18:43 +05:30
|
|
|
|
program_invocation_name = program_invocation_short_name;
|
2013-02-20 23:01:48 +05:30
|
|
|
|
#endif
|
2002-11-29 04:39:48 +05:30
|
|
|
|
setlocale(LC_ALL, "");
|
2011-12-07 17:57:21 +05:30
|
|
|
|
bindtextdomain(PACKAGE, LOCALEDIR);
|
|
|
|
|
textdomain(PACKAGE);
|
2012-03-23 18:02:24 +05:30
|
|
|
|
atexit(close_stdout);
|
2002-11-29 04:39:48 +05:30
|
|
|
|
|
2018-04-23 16:04:08 +05:30
|
|
|
|
interval_string = getenv("WATCH_INTERVAL");
|
2020-05-12 15:00:28 +05:30
|
|
|
|
if(interval_string != NULL)
|
2018-04-23 16:04:08 +05:30
|
|
|
|
interval = strtod_nol_or_err(interval_string, _("Could not parse interval from WATCH_INTERVAL"));
|
|
|
|
|
|
2011-06-05 18:35:47 +05:30
|
|
|
|
while ((optc =
|
2023-01-17 15:15:48 +05:30
|
|
|
|
getopt_long(argc, argv, "+bced::ghq:n:prtwvx", longopts, (int *)0))
|
2002-11-29 04:39:48 +05:30
|
|
|
|
!= EOF) {
|
|
|
|
|
switch (optc) {
|
2009-11-24 05:30:43 +05:30
|
|
|
|
case 'b':
|
2012-03-10 17:59:34 +05:30
|
|
|
|
flags |= WATCH_BEEP;
|
2009-11-24 05:30:43 +05:30
|
|
|
|
break;
|
2011-06-05 18:35:47 +05:30
|
|
|
|
case 'c':
|
2012-03-10 17:59:34 +05:30
|
|
|
|
flags |= WATCH_COLOR;
|
2011-06-05 18:35:47 +05:30
|
|
|
|
break;
|
2002-11-29 04:39:48 +05:30
|
|
|
|
case 'd':
|
2012-03-10 17:59:34 +05:30
|
|
|
|
flags |= WATCH_DIFF;
|
2002-11-29 04:39:48 +05:30
|
|
|
|
if (optarg)
|
2012-03-10 17:59:34 +05:30
|
|
|
|
flags |= WATCH_CUMUL;
|
2002-11-29 04:39:48 +05:30
|
|
|
|
break;
|
2011-06-05 18:35:47 +05:30
|
|
|
|
case 'e':
|
2012-03-10 17:59:34 +05:30
|
|
|
|
flags |= WATCH_ERREXIT;
|
2002-11-29 04:39:48 +05:30
|
|
|
|
break;
|
2012-01-26 20:12:37 +05:30
|
|
|
|
case 'g':
|
2012-03-10 17:59:34 +05:30
|
|
|
|
flags |= WATCH_CHGEXIT;
|
2012-01-26 20:12:37 +05:30
|
|
|
|
break;
|
2022-04-01 01:06:57 +05:30
|
|
|
|
case 'q':
|
|
|
|
|
flags |= WATCH_EQUEXIT;
|
|
|
|
|
max_cycles = strtod_nol_or_err(optarg, _("failed to parse argument"));
|
|
|
|
|
break;
|
2023-01-17 15:15:48 +05:30
|
|
|
|
case 'r':
|
|
|
|
|
flags |= WATCH_NORERUN;
|
|
|
|
|
break;
|
2003-02-09 12:57:16 +05:30
|
|
|
|
case 't':
|
|
|
|
|
show_title = 0;
|
|
|
|
|
break;
|
2020-10-19 16:33:44 +05:30
|
|
|
|
case 'w':
|
|
|
|
|
line_wrap = 0;
|
|
|
|
|
break;
|
2009-11-24 05:30:43 +05:30
|
|
|
|
case 'x':
|
2012-03-10 17:59:34 +05:30
|
|
|
|
flags |= WATCH_EXEC;
|
2009-11-24 05:30:43 +05:30
|
|
|
|
break;
|
2002-11-29 04:39:48 +05:30
|
|
|
|
case 'n':
|
2016-07-03 11:44:36 +05:30
|
|
|
|
interval = strtod_nol_or_err(optarg, _("failed to parse argument"));
|
2002-11-29 04:39:48 +05:30
|
|
|
|
break;
|
2009-11-24 05:30:46 +05:30
|
|
|
|
case 'p':
|
|
|
|
|
precise_timekeeping = 1;
|
|
|
|
|
break;
|
2011-06-05 18:35:47 +05:30
|
|
|
|
case 'h':
|
|
|
|
|
usage(stdout);
|
2002-11-29 04:39:48 +05:30
|
|
|
|
break;
|
2011-06-05 18:35:47 +05:30
|
|
|
|
case 'v':
|
2011-10-09 16:42:04 +05:30
|
|
|
|
printf(PROCPS_NG_VERSION);
|
2011-06-05 18:35:47 +05:30
|
|
|
|
return EXIT_SUCCESS;
|
2002-11-29 04:39:48 +05:30
|
|
|
|
default:
|
2011-06-05 18:35:47 +05:30
|
|
|
|
usage(stderr);
|
2002-11-29 04:39:48 +05:30
|
|
|
|
break;
|
|
|
|
|
}
|
2002-02-02 04:17:29 +05:30
|
|
|
|
}
|
2002-11-29 04:39:48 +05:30
|
|
|
|
|
2018-04-23 16:04:08 +05:30
|
|
|
|
if (interval < 0.1)
|
|
|
|
|
interval = 0.1;
|
|
|
|
|
if (interval > UINT_MAX)
|
|
|
|
|
interval = UINT_MAX;
|
|
|
|
|
|
2002-11-29 04:39:48 +05:30
|
|
|
|
if (optind >= argc)
|
2011-06-05 18:35:47 +05:30
|
|
|
|
usage(stderr);
|
2002-11-29 04:39:48 +05:30
|
|
|
|
|
2011-06-05 18:35:47 +05:30
|
|
|
|
/* save for later */
|
|
|
|
|
command_argv = &(argv[optind]);
|
2009-11-24 05:30:43 +05:30
|
|
|
|
|
2011-10-10 00:59:26 +05:30
|
|
|
|
command = xstrdup(argv[optind++]);
|
2002-11-29 04:39:48 +05:30
|
|
|
|
command_length = strlen(command);
|
|
|
|
|
for (; optind < argc; optind++) {
|
|
|
|
|
char *endp;
|
|
|
|
|
int s = strlen(argv[optind]);
|
2011-06-05 18:35:47 +05:30
|
|
|
|
/* space and \0 */
|
2011-10-10 00:59:26 +05:30
|
|
|
|
command = xrealloc(command, command_length + s + 2);
|
2002-11-29 04:39:48 +05:30
|
|
|
|
endp = command + command_length;
|
|
|
|
|
*endp = ' ';
|
|
|
|
|
memcpy(endp + 1, argv[optind], s);
|
2011-06-05 18:35:47 +05:30
|
|
|
|
/* space then string length */
|
|
|
|
|
command_length += 1 + s;
|
2002-11-29 04:39:48 +05:30
|
|
|
|
command[command_length] = '\0';
|
2002-02-02 04:17:29 +05:30
|
|
|
|
}
|
|
|
|
|
|
2011-12-20 16:42:37 +05:30
|
|
|
|
#ifdef WITH_WATCH8BIT
|
2011-06-05 18:35:47 +05:30
|
|
|
|
/* convert to wide for printing purposes */
|
|
|
|
|
/*mbstowcs(NULL, NULL, 0); */
|
2009-11-04 00:54:27 +05:30
|
|
|
|
wcommand_characters = mbstowcs(NULL, command, 0);
|
2011-06-05 18:35:47 +05:30
|
|
|
|
if (wcommand_characters < 0) {
|
2012-01-14 03:08:47 +05:30
|
|
|
|
fprintf(stderr, _("unicode handling error\n"));
|
2011-06-05 18:35:47 +05:30
|
|
|
|
exit(EXIT_FAILURE);
|
2009-11-04 00:54:27 +05:30
|
|
|
|
}
|
2011-06-05 18:35:47 +05:30
|
|
|
|
wcommand =
|
|
|
|
|
(wchar_t *) malloc((wcommand_characters + 1) * sizeof(wcommand));
|
|
|
|
|
if (wcommand == NULL) {
|
2012-01-14 03:08:47 +05:30
|
|
|
|
fprintf(stderr, _("unicode handling error (malloc)\n"));
|
2011-06-05 18:35:47 +05:30
|
|
|
|
exit(EXIT_FAILURE);
|
2009-11-04 00:54:27 +05:30
|
|
|
|
}
|
2011-06-05 18:35:47 +05:30
|
|
|
|
mbstowcs(wcommand, command, wcommand_characters + 1);
|
|
|
|
|
#endif /* WITH_WATCH8BIT */
|
2009-11-04 00:54:27 +05:30
|
|
|
|
|
2002-11-29 04:39:48 +05:30
|
|
|
|
get_terminal_size();
|
|
|
|
|
|
2011-06-05 18:35:47 +05:30
|
|
|
|
/* Catch keyboard interrupts so we can put tty back in a sane
|
|
|
|
|
* state. */
|
2002-11-29 04:39:48 +05:30
|
|
|
|
signal(SIGINT, die);
|
|
|
|
|
signal(SIGTERM, die);
|
|
|
|
|
signal(SIGHUP, die);
|
|
|
|
|
signal(SIGWINCH, winch_handler);
|
|
|
|
|
|
|
|
|
|
/* Set up tty for curses use. */
|
|
|
|
|
curses_started = 1;
|
|
|
|
|
initscr();
|
2012-03-10 17:59:34 +05:30
|
|
|
|
if (flags & WATCH_COLOR) {
|
2011-06-05 18:35:47 +05:30
|
|
|
|
if (has_colors()) {
|
|
|
|
|
start_color();
|
|
|
|
|
use_default_colors();
|
|
|
|
|
init_ansi_colors();
|
2012-03-10 17:59:34 +05:30
|
|
|
|
} else {
|
2019-09-21 11:33:28 +05:30
|
|
|
|
flags &= ~WATCH_COLOR;
|
2012-03-10 17:59:34 +05:30
|
|
|
|
}
|
2011-06-05 18:35:47 +05:30
|
|
|
|
}
|
2002-11-29 04:39:48 +05:30
|
|
|
|
nonl();
|
|
|
|
|
noecho();
|
|
|
|
|
cbreak();
|
|
|
|
|
|
2009-11-24 05:30:46 +05:30
|
|
|
|
if (precise_timekeeping)
|
|
|
|
|
next_loop = get_time_usec();
|
|
|
|
|
|
2012-03-10 17:59:34 +05:30
|
|
|
|
while (1) {
|
2002-11-29 04:39:48 +05:30
|
|
|
|
if (screen_size_changed) {
|
|
|
|
|
get_terminal_size();
|
|
|
|
|
resizeterm(height, width);
|
|
|
|
|
clear();
|
|
|
|
|
/* redrawwin(stdscr); */
|
|
|
|
|
screen_size_changed = 0;
|
|
|
|
|
first_screen = 1;
|
2002-02-02 04:17:29 +05:30
|
|
|
|
}
|
2002-11-29 04:39:48 +05:30
|
|
|
|
|
2012-03-10 17:59:34 +05:30
|
|
|
|
if (show_title)
|
2012-05-20 12:38:29 +05:30
|
|
|
|
#ifdef WITH_WATCH8BIT
|
2016-07-09 08:57:23 +05:30
|
|
|
|
output_header(wcommand, wcommand_characters, interval);
|
2012-05-20 12:38:29 +05:30
|
|
|
|
#else
|
2012-03-10 17:59:34 +05:30
|
|
|
|
output_header(command, interval);
|
2012-05-20 12:38:29 +05:30
|
|
|
|
#endif /* WITH_WATCH8BIT */
|
2002-02-02 04:17:29 +05:30
|
|
|
|
|
2023-01-17 15:15:48 +05:30
|
|
|
|
if (!(flags & WATCH_NORERUN) ||
|
|
|
|
|
get_time_usec() - last_run > interval * USECS_PER_SEC) {
|
|
|
|
|
last_run = get_time_usec();
|
|
|
|
|
int exit = run_command(command, command_argv);
|
|
|
|
|
|
|
|
|
|
if (flags & WATCH_EQUEXIT) {
|
|
|
|
|
if (cycle_count == max_cycles && exit) {
|
|
|
|
|
break;
|
|
|
|
|
} else if (exit) {
|
|
|
|
|
cycle_count++;
|
|
|
|
|
} else {
|
|
|
|
|
cycle_count = 0;
|
|
|
|
|
}
|
|
|
|
|
} else if (exit) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
refresh();
|
|
|
|
|
}
|
2014-09-06 14:16:27 +05:30
|
|
|
|
|
2009-11-24 05:30:46 +05:30
|
|
|
|
if (precise_timekeeping) {
|
|
|
|
|
watch_usec_t cur_time = get_time_usec();
|
2011-06-05 18:35:47 +05:30
|
|
|
|
next_loop += USECS_PER_SEC * interval;
|
2009-11-24 05:30:46 +05:30
|
|
|
|
if (cur_time < next_loop)
|
|
|
|
|
usleep(next_loop - cur_time);
|
|
|
|
|
} else
|
2013-08-25 13:13:20 +05:30
|
|
|
|
if (interval < UINT_MAX / USECS_PER_SEC)
|
|
|
|
|
usleep(interval * USECS_PER_SEC);
|
|
|
|
|
else
|
|
|
|
|
sleep(interval);
|
2012-03-10 17:59:34 +05:30
|
|
|
|
}
|
2002-02-02 04:17:29 +05:30
|
|
|
|
|
2012-03-11 06:05:08 +05:30
|
|
|
|
endwin();
|
|
|
|
|
return EXIT_SUCCESS;
|
2002-02-02 04:17:29 +05:30
|
|
|
|
}
|