From: Darafei Praliaskouski Date: Sat, 9 May 2026 09:39:26 +0000 (+0400) Subject: feat(curses): add compact and scale controls X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=038ef43262861fd95034e918bb09ec3738ffd652;p=thirdparty%2Fmtr.git feat(curses): add compact and scale controls --- diff --git a/bash-completion/mtr b/bash-completion/mtr index bc60346..348b925 100644 --- a/bash-completion/mtr +++ b/bash-completion/mtr @@ -56,7 +56,8 @@ _mtr_module() --interval --gracetime --tos --mpls --timeout --mark --report --report-wide --report-on-exit --report-cycles --json --xml --csv --raw --split - --curses --displaymode --gtk --no-dns --show-ips --order --ipinfo + --curses --displaymode --compact --scale --gtk + --no-dns --show-ips --order --ipinfo --aslookup --help --version ' COMPREPLY=( $(compgen -W "${OPTS[*]}" -- "$cur") ) diff --git a/man/mtr.8.in b/man/mtr.8.in index 80bdf23..59c68a7 100644 --- a/man/mtr.8.in +++ b/man/mtr.8.in @@ -32,6 +32,12 @@ mtr \- a network diagnostic tool .BI \--displaymode \ MODE\c ] [\c +.B \-\-compact\c +] +[\c +.BI \--scale \ SCALE\c +] +[\c .B \-\-raw\c ] [\c @@ -253,6 +259,22 @@ buckets, and .B > marks values above the last displayed bucket. .TP +.B -\-compact +Use this option to start the curses interface in compact mode. +.TP +.B -\-scale \fISCALE +Use this option to select fixed latency thresholds for the stripchart +display modes. +.I SCALE +can be +.BR fast , +.BR average , +.BR slow , +or nine strictly increasing millisecond thresholds separated by colons, +for example +.BR 5:15:25:35:45:55:101:200:400 . +Without this option, the stripchart keeps using the dynamic scale. +.TP .B \-g\fR, \fB\-\-gtk Use this option to force .B mtr diff --git a/ui/curses.c b/ui/curses.c index 01abc7f..77b33b2 100644 --- a/ui/curses.c +++ b/ui/curses.c @@ -20,6 +20,7 @@ #include "mtr.h" +#include #include #ifdef __CYGWIN__ #include @@ -76,27 +77,29 @@ #include "utils.h" -enum { NUM_FACTORS = 8 }; +enum { NUM_FACTORS = MTR_SCALE_FACTORS }; static double factors[NUM_FACTORS]; static int scale[NUM_FACTORS]; static char block_map[NUM_FACTORS]; #ifdef WITH_BRAILLE_DISPLAY static const wchar_t *braille_map[NUM_FACTORS] = { - L"⣀", L"⣀", L"⣤", L"⣤", L"⣶", L"⣶", L"⣿", L"⣿" + L"⣀", L"⣀", L"⣤", L"⣤", L"⣦", L"⣦", L"⣶", L"⣶", L"⣿", L"⣿" }; #endif enum { black = 1, red, green, yellow, blue, magenta, cyan, white }; static const int block_col[NUM_FACTORS + 1] = { COLOR_PAIR(red) | A_BOLD, - A_NORMAL, - COLOR_PAIR(green), COLOR_PAIR(green) | A_BOLD, + COLOR_PAIR(green) | A_BOLD, + COLOR_PAIR(green) | A_BOLD, + COLOR_PAIR(yellow) | A_BOLD, COLOR_PAIR(yellow) | A_BOLD, COLOR_PAIR(magenta) | A_BOLD, - COLOR_PAIR(magenta), + COLOR_PAIR(red) | A_BOLD, + COLOR_PAIR(red) | A_BOLD, COLOR_PAIR(red), - COLOR_PAIR(red) | A_BOLD + COLOR_PAIR(red) }; static void pwcenter( @@ -553,6 +556,14 @@ static void mtr_gen_scale( for (i = 0; i < NUM_FACTORS; i++) { scale[i] = 0; } + if (ctl->fixed_scale) { + for (i = 0; i < MTR_SCALE_THRESHOLDS; i++) { + scale[i] = ctl->scale[i]; + } + scale[NUM_FACTORS - 1] = INT_MAX; + return; + } + max = net_max(ctl); for (at = ctl->display_offset; at < max; at++) { saved = net_saved_pings(at); @@ -586,7 +597,7 @@ static void mtr_curses_init( } /* Initialize block_map. The block_split is always smaller than 9 */ - block_split = (NUM_FACTORS - 2) / 2; + block_split = NUM_FACTORS / 2; for (i = 1; i <= block_split; i++) { block_map[i] = '0' + i; } @@ -788,7 +799,7 @@ static void mtr_fill_graph( attrset(A_NORMAL); } else { if (ctl->display_mode == DisplayModeBlockmap) { - if (saved[i] > scale[6]) { + if (saved[i] > scale[NUM_FACTORS - 2]) { printw("%c", block_map[NUM_FACTORS - 1]); } else { printw("."); diff --git a/ui/mtr.c b/ui/mtr.c index fd97680..3214122 100644 --- a/ui/mtr.c +++ b/ui/mtr.c @@ -138,8 +138,10 @@ static void __attribute__ ((__noreturn__)) usage(FILE * out) fputs(" -p, --split split output\n", out); #ifdef HAVE_CURSES fputs(" -t, --curses use curses terminal interface\n", out); -#endif fputs(" --displaymode MODE select initial display mode\n", out); + fputs(" --compact start curses interface in compact mode\n", out); + fputs(" --scale SCALE set stripchart scale thresholds\n", out); +#endif #ifdef HAVE_GTK fputs(" -g, --gtk use GTK+ xwindow interface\n", out); #endif @@ -405,6 +407,89 @@ static void print_version( } +#ifdef HAVE_CURSES +static void set_fixed_scale( + struct mtr_ctl *ctl, + const int *thresholds) +{ + int i; + + for (i = 0; i < MTR_SCALE_THRESHOLDS; i++) { + ctl->scale[i] = thresholds[i] * 1000; + } + ctl->fixed_scale = 1; +} + + +static void parse_scale( + struct mtr_ctl *ctl, + const char *scale_arg) +{ + static const int fast_scale[MTR_SCALE_THRESHOLDS] = { + 1, 2, 3, 4, 5, 10, 20, 40, 80 + }; + static const int average_scale[MTR_SCALE_THRESHOLDS] = { + 5, 15, 25, 35, 45, 55, 101, 200, 400 + }; + static const int slow_scale[MTR_SCALE_THRESHOLDS] = { + 50, 100, 150, 200, 300, 500, 750, 1000, 2000 + }; + const char *cursor = scale_arg; + int thresholds[MTR_SCALE_THRESHOLDS]; + int previous = -1; + int i; + + if (!strcmp(scale_arg, "fast")) { + set_fixed_scale(ctl, fast_scale); + return; + } + if (!strcmp(scale_arg, "average")) { + set_fixed_scale(ctl, average_scale); + return; + } + if (!strcmp(scale_arg, "slow")) { + set_fixed_scale(ctl, slow_scale); + return; + } + + for (i = 0; i < MTR_SCALE_THRESHOLDS; i++) { + char *end; + long threshold; + + errno = 0; + threshold = strtol(cursor, &end, 10); + if (cursor == end || errno || threshold < 0 || + threshold > INT_MAX / 1000) { + error(EXIT_FAILURE, 0, "invalid scale threshold: %s", scale_arg); + } + if (threshold <= previous) { + error(EXIT_FAILURE, 0, + "scale thresholds must be strictly increasing: %s", + scale_arg); + } + + thresholds[i] = threshold; + previous = threshold; + + if (i == MTR_SCALE_THRESHOLDS - 1) { + if (*end) { + error(EXIT_FAILURE, 0, + "scale expects %d thresholds: %s", + MTR_SCALE_THRESHOLDS, scale_arg); + } + } else if (*end != ':') { + error(EXIT_FAILURE, 0, + "scale expects %d colon-separated thresholds: %s", + MTR_SCALE_THRESHOLDS, scale_arg); + } + cursor = end + 1; + } + + set_fixed_scale(ctl, thresholds); +} +#endif + + static void parse_arg( struct mtr_ctl *ctl, names_t ** names, @@ -422,12 +507,14 @@ static void parse_arg( enum { OPT_DISPLAYMODE = CHAR_MAX + 1, OPT_REPORT_ON_EXIT = CHAR_MAX + 2, - OPT_IPINFO4 = CHAR_MAX + 3, + OPT_SCALE = CHAR_MAX + 3, + OPT_IPINFO4 = CHAR_MAX + 4, + OPT_COMPACT = CHAR_MAX + 5, #ifdef ENABLE_IPV6 - OPT_IPINFO6 = CHAR_MAX + 4, - OPT_CACHE = CHAR_MAX + 5, + OPT_IPINFO6 = CHAR_MAX + 6, + OPT_CACHE = CHAR_MAX + 7, #else - OPT_CACHE = CHAR_MAX + 4, + OPT_CACHE = CHAR_MAX + 6, #endif /* ifdef ENABLE_IPV6 */ }; static const struct option long_options[] = { @@ -456,7 +543,11 @@ static void parse_arg( #ifdef HAVE_JANSSON {"json", 0, NULL, 'j'}, #endif +#ifdef HAVE_CURSES {"displaymode", 1, NULL, OPT_DISPLAYMODE}, + {"compact", 0, NULL, OPT_COMPACT}, + {"scale", 1, NULL, OPT_SCALE}, +#endif {"split", 0, NULL, 'p'}, /* BL */ /* maybe above should change to -d 'x' */ @@ -569,6 +660,7 @@ static void parse_arg( ctl->DisplayMode = DisplayXML; break; +#ifdef HAVE_CURSES case OPT_DISPLAYMODE: ctl->display_mode = strtoint_or_err(optarg, "invalid argument"); @@ -576,6 +668,13 @@ static void parse_arg( error(EXIT_FAILURE, 0, "value out of range (%d - %d): %s", DisplayModeDefault, (DisplayModeMAX - 1), optarg); break; + case OPT_COMPACT: + ctl->CompactLayout = 1; + break; + case OPT_SCALE: + parse_scale(ctl, optarg); + break; +#endif case 'c': ctl->MaxPing = strtoint_or_err(optarg, "invalid argument"); diff --git a/ui/mtr.h b/ui/mtr.h index 64cdc4a..f3ad796 100644 --- a/ui/mtr.h +++ b/ui/mtr.h @@ -64,6 +64,11 @@ typedef int time_t; #define MAXFLD 20 /* max stats fields to display */ #define FLD_INDEX_SZ 256 +enum { + MTR_SCALE_FACTORS = 10, + MTR_SCALE_THRESHOLDS = MTR_SCALE_FACTORS - 1 +}; + /* net related definitions */ #define SAVED_PINGS 400 #define MAX_PATH 128 @@ -116,6 +121,7 @@ struct mtr_ctl { int cache_timeout; /* seconds to skip probes for recently seen hops */ unsigned char fld_active[2 * MAXFLD]; /* SO_MARK to set for ping packet */ int display_mode; /* display mode selector */ + int scale[MTR_SCALE_THRESHOLDS]; /* fixed stripchart scale thresholds */ int fld_index[FLD_INDEX_SZ]; /* default display field (defined by key in net.h) and order */ char available_options[MAXFLD]; int display_offset; /* only used in text mode */ @@ -126,7 +132,7 @@ struct mtr_ctl { use_dns:1, cache:1, show_ips:1, enablempls:1, dns:1, reportwide:1, Interactive:1, DisplayMode:5, - CompactLayout:1, ReportOnExit:1; + CompactLayout:1, ReportOnExit:1, fixed_scale:1; #ifdef HAVE_IPINFO #ifdef ENABLE_IPV6 char *ipinfo_provider6;