Annotation of embedaddon/mtr/ui/curses.c, revision 1.1.1.1
1.1 misho 1: /*
2: mtr -- a network diagnostic tool
3: Copyright (C) 1997,1998 Matt Kimball
4:
5: This program is free software; you can redistribute it and/or modify
6: it under the terms of the GNU General Public License version 2 as
7: published by the Free Software Foundation.
8:
9: This program is distributed in the hope that it will be useful,
10: but WITHOUT ANY WARRANTY; without even the implied warranty of
11: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12: GNU General Public License for more details.
13:
14: You should have received a copy of the GNU General Public License
15: along with this program; if not, write to the Free Software
16: Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17: */
18:
19: #include "config.h"
20:
21: #include "mtr.h"
22:
23: #include <strings.h>
24: #include <unistd.h>
25:
26: #include <ctype.h>
27: #include <stdlib.h>
28: #include <string.h>
29: #include <time.h>
30:
31: /* MacOSX may need this before socket.h...*/
32: #if defined(HAVE_SYS_TYPES_H)
33: #include <sys/types.h>
34: #endif
35:
36: #include <sys/socket.h>
37: #include <netinet/in.h>
38: #include <arpa/inet.h>
39:
40: #if defined(HAVE_NCURSES_H)
41: #include <ncurses.h>
42: #elif defined(HAVE_NCURSES_CURSES_H)
43: #include <ncurses/curses.h>
44: #elif defined(HAVE_CURSES_H)
45: #include <curses.h>
46: #elif defined(HAVE_CURSESX_H)
47: #include <cursesX.h>
48: #else
49: #error No curses header file available
50: #endif
51:
52: /* This go-around is needed only when compiling with antique version of curses.
53: getmaxyx is part of Technical Standard X/Open Curses Issue 4, Version 2 (1996).
54: http://pubs.opengroup.org/onlinepubs/9693989999/toc.pdf see page 106 */
55: #ifndef getmaxyx
56: #define getmaxyx(win,y,x) ((y) = (win)->_maxy + 1, (x) = (win)->_maxx + 1)
57: #endif
58:
59: #include "mtr.h"
60: #include "mtr-curses.h"
61: #include "net.h"
62: #include "dns.h"
63: #include "asn.h"
64: #include "display.h"
65: #include "utils.h"
66:
67:
68: enum { NUM_FACTORS = 8 };
69: static double factors[NUM_FACTORS];
70: static int scale[NUM_FACTORS];
71: static char block_map[NUM_FACTORS];
72:
73: enum { black = 1, red, green, yellow, blue, magenta, cyan, white };
74: static const int block_col[NUM_FACTORS + 1] = {
75: COLOR_PAIR(red) | A_BOLD,
76: A_NORMAL,
77: COLOR_PAIR(green),
78: COLOR_PAIR(green) | A_BOLD,
79: COLOR_PAIR(yellow) | A_BOLD,
80: COLOR_PAIR(magenta) | A_BOLD,
81: COLOR_PAIR(magenta),
82: COLOR_PAIR(red),
83: COLOR_PAIR(red) | A_BOLD
84: };
85:
86: static void pwcenter(
87: char *str)
88: {
89: int maxx;
90: size_t cx;
91: int __unused_int ATTRIBUTE_UNUSED;
92:
93: getmaxyx(stdscr, __unused_int, maxx);
94: cx = (size_t) (maxx - strlen(str)) / 2;
95: printw("%*s%s", (int) cx, "", str);
96: }
97:
98:
99: static char *format_number(
100: int n,
101: int w,
102: char *buf)
103: {
104: if (w != 5)
105: /* XXX todo: implement w != 5.. */
106: snprintf(buf, w + 1, "%s", "unimpl");
107: else if (n < 100000)
108: /* buf is good as-is */ ;
109: else if (n < 1000000)
110: snprintf(buf, w + 1, "%3dk%1d", n / 1000, (n % 1000) / 100);
111: else if (n < 10000000)
112: snprintf(buf, w + 1, "%1dM%03d", n / 1000000,
113: (n % 1000000) / 1000);
114: else if (n < 100000000)
115: snprintf(buf, w + 1, "%2dM%02d", n / 1000000,
116: (n % 1000000) / 10000);
117: else if (n < 1000000000)
118: snprintf(buf, w + 1, "%3dM%01d", n / 1000000,
119: (n % 1000000) / 100000);
120: else /* if (n < 10000000000) */
121: snprintf(buf, w + 1, "%1dG%03d", n / 1000000000,
122: (n % 1000000000) / 1000000);
123:
124: return buf;
125: }
126:
127:
128: int mtr_curses_keyaction(
129: struct mtr_ctl *ctl)
130: {
131: int c = getch();
132: int i = 0;
133: float f = 0.0;
134: char buf[MAXFLD + 1];
135:
136: if (c == 'Q') { /* must be checked before c = tolower(c) */
137: mvprintw(2, 0, "Type of Service(tos): %d\n", ctl->tos);
138: mvprintw(3, 0,
139: "default 0x00, min cost 0x02, rel 0x04,, thr 0x08, low del 0x10...\n");
140: move(2, 22);
141: refresh();
142: while ((c = getch()) != '\n' && i < MAXFLD) {
143: attron(A_BOLD);
144: printw("%c", c);
145: attroff(A_BOLD);
146: refresh();
147: buf[i++] = c; /* need more checking on 'c' */
148: }
149: buf[i] = '\0';
150: ctl->tos = atoi(buf);
151: if (ctl->tos > 255 || ctl->tos < 0)
152: ctl->tos = 0;
153: return ActionNone;
154: }
155:
156: c = tolower(c);
157:
158: switch (c) {
159: case 'q':
160: case 3:
161: return ActionQuit;
162: case 12:
163: return ActionClear;
164: case 19:
165: case 'p':
166: return ActionPause;
167: case 17:
168: case ' ':
169: return ActionResume;
170: case 'r':
171: return ActionReset;
172: case 'd':
173: return ActionDisplay;
174: case 'e':
175: return ActionMPLS;
176: case 'n':
177: return ActionDNS;
178: #ifdef HAVE_IPINFO
179: case 'y':
180: return ActionII;
181: case 'z':
182: return ActionAS;
183: #endif
184: case '+':
185: return ActionScrollDown;
186: case '-':
187: return ActionScrollUp;
188: case 's':
189: mvprintw(2, 0, "Change Packet Size: %d\n", ctl->cpacketsize);
190: mvprintw(3, 0, "Size Range: %d-%d, < 0:random.\n", MINPACKET,
191: MAXPACKET);
192: move(2, 20);
193: refresh();
194: while ((c = getch()) != '\n' && i < MAXFLD) {
195: attron(A_BOLD);
196: printw("%c", c);
197: attroff(A_BOLD);
198: refresh();
199: buf[i++] = c; /* need more checking on 'c' */
200: }
201: buf[i] = '\0';
202: ctl->cpacketsize = atoi(buf);
203: return ActionNone;
204: case 'b':
205: mvprintw(2, 0, "Ping Bit Pattern: %d\n", ctl->bitpattern);
206: mvprintw(3, 0, "Pattern Range: 0(0x00)-255(0xff), <0 random.\n");
207: move(2, 18);
208: refresh();
209: while ((c = getch()) != '\n' && i < MAXFLD) {
210: attron(A_BOLD);
211: printw("%c", c);
212: attroff(A_BOLD);
213: refresh();
214: buf[i++] = c; /* need more checking on 'c' */
215: }
216: buf[i] = '\0';
217: ctl->bitpattern = atoi(buf);
218: if (ctl->bitpattern > 255)
219: ctl->bitpattern = -1;
220: return ActionNone;
221: case 'i':
222: mvprintw(2, 0, "Interval : %0.0f\n\n", ctl->WaitTime);
223: move(2, 11);
224: refresh();
225: while ((c = getch()) != '\n' && i < MAXFLD) {
226: attron(A_BOLD);
227: printw("%c", c);
228: attroff(A_BOLD);
229: refresh();
230: buf[i++] = c; /* need more checking on 'c' */
231: }
232: buf[i] = '\0';
233:
234: f = atof(buf);
235:
236: if (f <= 0.0)
237: return ActionNone;
238: if (getuid() != 0 && f < 1.0)
239: return ActionNone;
240: ctl->WaitTime = f;
241:
242: return ActionNone;
243: case 'f':
244: mvprintw(2, 0, "First TTL: %d\n\n", ctl->fstTTL);
245: move(2, 11);
246: refresh();
247: while ((c = getch()) != '\n' && i < MAXFLD) {
248: attron(A_BOLD);
249: printw("%c", c);
250: attroff(A_BOLD);
251: refresh();
252: buf[i++] = c; /* need more checking on 'c' */
253: }
254: buf[i] = '\0';
255: i = atoi(buf);
256:
257: if (i < 1 || i > ctl->maxTTL)
258: return ActionNone;
259: ctl->fstTTL = i;
260:
261: return ActionNone;
262: case 'm':
263: mvprintw(2, 0, "Max TTL: %d\n\n", ctl->maxTTL);
264: move(2, 9);
265: refresh();
266: while ((c = getch()) != '\n' && i < MAXFLD) {
267: attron(A_BOLD);
268: printw("%c", c);
269: attroff(A_BOLD);
270: refresh();
271: buf[i++] = c; /* need more checking on 'c' */
272: }
273: buf[i] = '\0';
274: i = atoi(buf);
275:
276: if (i < ctl->fstTTL || i > (MaxHost - 1))
277: return ActionNone;
278: ctl->maxTTL = i;
279:
280: return ActionNone;
281: /* fields to display & their ordering */
282: case 'o':
283: mvprintw(2, 0, "Fields: %s\n\n", ctl->fld_active);
284:
285: for (i = 0; i < MAXFLD; i++) {
286: if (data_fields[i].descr != NULL)
287: printw(" %s\n", data_fields[i].descr);
288: }
289: printw("\n");
290: move(2, 8); /* length of "Fields: " */
291: refresh();
292:
293: i = 0;
294: while ((c = getch()) != '\n' && i < MAXFLD) {
295: if (strchr(ctl->available_options, c)) {
296: attron(A_BOLD);
297: printw("%c", c);
298: attroff(A_BOLD);
299: refresh();
300: buf[i++] = c; /* Only permit values in "available_options" be entered */
301: } else {
302: printf("\a"); /* Illegal character. Beep, ring the bell. */
303: }
304: }
305: buf[i] = '\0';
306: if (strlen(buf) > 0)
307: xstrncpy(ctl->fld_active, buf, 2 * MAXFLD);
308:
309: return ActionNone;
310: case 'j':
311: if (strchr(ctl->fld_active, 'N'))
312: /* GeoMean and jitter */
313: xstrncpy(ctl->fld_active, "DR AGJMXI", 2 * MAXFLD);
314: else
315: /* default */
316: xstrncpy(ctl->fld_active, "LS NABWV", 2 * MAXFLD);
317: return ActionNone;
318: case 'u':
319: switch (ctl->mtrtype) {
320: case IPPROTO_ICMP:
321: case IPPROTO_TCP:
322: ctl->mtrtype = IPPROTO_UDP;
323: break;
324: case IPPROTO_UDP:
325: ctl->mtrtype = IPPROTO_ICMP;
326: break;
327: }
328: return ActionNone;
329: case 't':
330: switch (ctl->mtrtype) {
331: case IPPROTO_ICMP:
332: case IPPROTO_UDP:
333: ctl->mtrtype = IPPROTO_TCP;
334: break;
335: case IPPROTO_TCP:
336: ctl->mtrtype = IPPROTO_ICMP;
337: break;
338: }
339: return ActionNone;
340: /* reserve to display help message -Min */
341: case '?':
342: case 'h':
343: mvprintw(2, 0, "Command:\n");
344: printw(" ?|h help\n");
345: printw(" p pause (SPACE to resume)\n");
346: printw(" d switching display mode\n");
347: printw(" e toggle MPLS information on/off\n");
348: printw(" n toggle DNS on/off\n");
349: printw(" r reset all counters\n");
350: printw
351: (" o str set the columns to display, default str='LRS N BAWV'\n");
352: printw
353: (" j toggle latency(LS NABWV)/jitter(DR AGJMXI) stats\n");
354: printw(" c <n> report cycle n, default n=infinite\n");
355: printw
356: (" i <n> set the ping interval to n seconds, default n=1\n");
357: printw
358: (" f <n> set the initial time-to-live(ttl), default n=1\n");
359: printw
360: (" m <n> set the max time-to-live, default n= # of hops\n");
361: printw(" s <n> set the packet size to n or random(n<0)\n");
362: printw
363: (" b <c> set ping bit pattern to c(0..255) or random(c<0)\n");
364: printw(" Q <t> set ping packet's TOS to t\n");
365: printw(" u switch between ICMP ECHO and UDP datagrams\n");
366: #ifdef HAVE_IPINFO
367: printw(" y switching IP info\n");
368: printw(" z toggle ASN info on/off\n");
369: #endif
370: printw("\n");
371: printw(" press any key to go back...");
372: getch(); /* read and ignore 'any key' */
373: return ActionNone;
374: default: /* ignore unknown input */
375: return ActionNone;
376: }
377: }
378:
379:
380: static void format_field(
381: char *dst,
382: int dst_length,
383: const char *format,
384: int n)
385: {
386: if (index(format, 'N')) {
387: *dst++ = ' ';
388: format_number(n, 5, dst);
389: } else if (strchr(format, 'f')) {
390: /* this is for fields where we measure integer microseconds but
391: display floating point miliseconds. Convert to float here. */
392: snprintf(dst, dst_length, format, n / 1000.0);
393: /* this was marked as a temporary hack over 10 years ago. -- REW */
394: } else {
395: snprintf(dst, dst_length, format, n);
396: }
397: }
398:
399: static void mtr_curses_hosts(
400: struct mtr_ctl *ctl,
401: int startstat)
402: {
403: int max;
404: int at;
405: struct mplslen *mpls, *mplss;
406: ip_t *addr, *addrs;
407: int y;
408: char *name;
409:
410: int i, j, k;
411: int hd_len;
412: char buf[1024];
413: int __unused_int ATTRIBUTE_UNUSED;
414:
415: max = net_max(ctl);
416:
417: for (at = net_min(ctl) + ctl->display_offset; at < max; at++) {
418: printw("%2d. ", at + 1);
419: addr = net_addr(at);
420: mpls = net_mpls(at);
421:
422: if (addrcmp((void *) addr, (void *) &ctl->unspec_addr, ctl->af) !=
423: 0) {
424: name = dns_lookup(ctl, addr);
425: if (!net_up(at))
426: attron(A_BOLD);
427: #ifdef HAVE_IPINFO
428: if (is_printii(ctl))
429: printw(fmt_ipinfo(ctl, addr));
430: #endif
431: if (name != NULL) {
432: if (ctl->show_ips)
433: printw("%s (%s)", name, strlongip(ctl, addr));
434: else
435: printw("%s", name);
436: } else {
437: printw("%s", strlongip(ctl, addr));
438: }
439: attroff(A_BOLD);
440:
441: getyx(stdscr, y, __unused_int);
442: move(y, startstat);
443:
444: /* net_xxx returns times in usecs. Just display millisecs */
445: hd_len = 0;
446: for (i = 0; i < MAXFLD; i++) {
447: /* Ignore options that don't exist */
448: /* On the other hand, we now check the input side. Shouldn't happen,
449: can't be careful enough. */
450: j = ctl->fld_index[ctl->fld_active[i]];
451: if (j == -1)
452: continue;
453: format_field(buf + hd_len, sizeof(buf) - hd_len,
454: data_fields[j].format,
455: data_fields[j].net_xxx(at));
456: hd_len += data_fields[j].length;
457: }
458: buf[hd_len] = 0;
459: printw("%s", buf);
460:
461: for (k = 0; k < mpls->labels && ctl->enablempls; k++) {
462: printw("\n [MPLS: Lbl %lu Exp %u S %u TTL %u]",
463: mpls->label[k], mpls->exp[k], mpls->s[k],
464: mpls->ttl[k]);
465: }
466:
467: /* Multi path */
468: for (i = 0; i < MAXPATH; i++) {
469: addrs = net_addrs(at, i);
470: mplss = net_mplss(at, i);
471: if (addrcmp((void *) addrs, (void *) addr, ctl->af) == 0)
472: continue;
473: if (addrcmp
474: ((void *) addrs, (void *) &ctl->unspec_addr,
475: ctl->af) == 0)
476: break;
477:
478: name = dns_lookup(ctl, addrs);
479: if (!net_up(at))
480: attron(A_BOLD);
481: printw("\n ");
482: #ifdef HAVE_IPINFO
483: if (is_printii(ctl))
484: printw(fmt_ipinfo(ctl, addrs));
485: #endif
486: if (name != NULL) {
487: if (ctl->show_ips)
488: printw("%s (%s)", name, strlongip(ctl, addrs));
489: else
490: printw("%s", name);
491: } else {
492: printw("%s", strlongip(ctl, addrs));
493: }
494: for (k = 0; k < mplss->labels && ctl->enablempls; k++) {
495: printw("\n [MPLS: Lbl %lu Exp %u S %u TTL %u]",
496: mplss->label[k], mplss->exp[k], mplss->s[k],
497: mplss->ttl[k]);
498: }
499: attroff(A_BOLD);
500: }
501:
502: } else {
503: printw("???");
504: }
505:
506: printw("\n");
507: }
508: move(2, 0);
509: }
510:
511: static void mtr_gen_scale(
512: struct mtr_ctl *ctl)
513: {
514: int *saved, i, max, at;
515: int range;
516: static int low_ms, high_ms;
517:
518: low_ms = 1000000;
519: high_ms = -1;
520:
521: for (i = 0; i < NUM_FACTORS; i++) {
522: scale[i] = 0;
523: }
524: max = net_max(ctl);
525: for (at = ctl->display_offset; at < max; at++) {
526: saved = net_saved_pings(at);
527: for (i = 0; i < SAVED_PINGS; i++) {
528: if (saved[i] < 0)
529: continue;
530: if (saved[i] < low_ms) {
531: low_ms = saved[i];
532: }
533: if (saved[i] > high_ms) {
534: high_ms = saved[i];
535: }
536: }
537: }
538: range = high_ms - low_ms;
539: for (i = 0; i < NUM_FACTORS; i++) {
540: scale[i] = low_ms + ((double) range * factors[i]);
541: }
542: }
543:
544: static void mtr_curses_init(
545: void)
546: {
547: int i;
548: int block_split;
549:
550: /* Initialize factors to a log scale. */
551: for (i = 0; i < NUM_FACTORS; i++) {
552: factors[i] = ((double) 1 / NUM_FACTORS) * (i + 1);
553: factors[i] *= factors[i]; /* Squared. */
554: }
555:
556: /* Initialize block_map. The block_split is always smaller than 9 */
557: block_split = (NUM_FACTORS - 2) / 2;
558: for (i = 1; i <= block_split; i++) {
559: block_map[i] = '0' + i;
560: }
561: for (i = block_split + 1; i < NUM_FACTORS - 1; i++) {
562: block_map[i] = 'a' + i - block_split - 1;
563: }
564: block_map[0] = '.';
565: block_map[NUM_FACTORS - 1] = '>';
566: }
567:
568: static void mtr_print_scaled(
569: int ms)
570: {
571: int i;
572:
573: for (i = 0; i < NUM_FACTORS; i++) {
574: if (ms <= scale[i]) {
575: attrset(block_col[i + 1]);
576: printw("%c", block_map[i]);
577: attrset(A_NORMAL);
578: return;
579: }
580: }
581: printw(">");
582: }
583:
584:
585: static void mtr_fill_graph(
586: struct mtr_ctl *ctl,
587: int at,
588: int cols)
589: {
590: int *saved;
591: int i;
592:
593: saved = net_saved_pings(at);
594: for (i = SAVED_PINGS - cols; i < SAVED_PINGS; i++) {
595: if (saved[i] == -2) {
596: printw(" ");
597: } else if (saved[i] == -1) {
598: attrset(block_col[0]);
599: printw("%c", '?');
600: attrset(A_NORMAL);
601: } else {
602: if (ctl->display_mode == DisplayModeBlockmap) {
603: if (saved[i] > scale[6]) {
604: printw("%c", block_map[NUM_FACTORS - 1]);
605: } else {
606: printw(".");
607: }
608: } else {
609: mtr_print_scaled(saved[i]);
610: }
611: }
612: }
613: }
614:
615:
616: static void mtr_curses_graph(
617: struct mtr_ctl *ctl,
618: int startstat,
619: int cols)
620: {
621: int max, at, y;
622: ip_t *addr;
623: char *name;
624: int __unused_int ATTRIBUTE_UNUSED;
625:
626: max = net_max(ctl);
627:
628: for (at = ctl->display_offset; at < max; at++) {
629: printw("%2d. ", at + 1);
630:
631: addr = net_addr(at);
632: if (!addr) {
633: printw("???\n");
634: continue;
635: }
636:
637: if (!net_up(at))
638: attron(A_BOLD);
639: if (addrcmp((void *) addr, (void *) &ctl->unspec_addr, ctl->af)) {
640: #ifdef HAVE_IPINFO
641: if (is_printii(ctl))
642: printw(fmt_ipinfo(ctl, addr));
643: #endif
644: name = dns_lookup(ctl, addr);
645: printw("%s", name ? name : strlongip(ctl, addr));
646: } else
647: printw("???");
648: attroff(A_BOLD);
649:
650: getyx(stdscr, y, __unused_int);
651: move(y, startstat);
652:
653: printw(" ");
654: mtr_fill_graph(ctl, at, cols);
655: printw("\n");
656: }
657: }
658:
659:
660: void mtr_curses_redraw(
661: struct mtr_ctl *ctl)
662: {
663: int maxx;
664: int startstat;
665: int rowstat;
666: time_t t;
667: int __unused_int ATTRIBUTE_UNUSED;
668:
669: int i, j;
670: int hd_len = 0;
671: char buf[1024];
672: char fmt[16];
673:
674:
675: erase();
676: getmaxyx(stdscr, __unused_int, maxx);
677:
678: rowstat = 5;
679:
680: move(0, 0);
681: attron(A_BOLD);
682: snprintf(buf, sizeof(buf), "%s%s%s", "My traceroute [v",
683: PACKAGE_VERSION, "]");
684: pwcenter(buf);
685: attroff(A_BOLD);
686:
687: mvprintw(1, 0, "%s (%s)", ctl->LocalHostname, net_localaddr());
688: t = time(NULL);
689: mvprintw(1, maxx - 25, iso_time(&t));
690: printw("\n");
691:
692: printw("Keys: ");
693: attron(A_BOLD);
694: printw("H");
695: attroff(A_BOLD);
696: printw("elp ");
697: attron(A_BOLD);
698: printw("D");
699: attroff(A_BOLD);
700: printw("isplay mode ");
701: attron(A_BOLD);
702: printw("R");
703: attroff(A_BOLD);
704: printw("estart statistics ");
705: attron(A_BOLD);
706: printw("O");
707: attroff(A_BOLD);
708: printw("rder of fields ");
709: attron(A_BOLD);
710: printw("q");
711: attroff(A_BOLD);
712: printw("uit\n");
713:
714: if (ctl->display_mode == DisplayModeDefault) {
715: for (i = 0; i < MAXFLD; i++) {
716: j = ctl->fld_index[ctl->fld_active[i]];
717: if (j < 0)
718: continue;
719:
720: snprintf(fmt, sizeof(fmt), "%%%ds", data_fields[j].length);
721: snprintf(buf + hd_len, sizeof(buf) - hd_len, fmt,
722: data_fields[j].title);
723: hd_len += data_fields[j].length;
724: }
725: attron(A_BOLD);
726: mvprintw(rowstat - 1, 0, " Host");
727: mvprintw(rowstat - 1, maxx - hd_len - 1, "%s", buf);
728: mvprintw(rowstat - 2, maxx - hd_len - 1,
729: " Packets Pings");
730: attroff(A_BOLD);
731:
732: move(rowstat, 0);
733: mtr_curses_hosts(ctl, maxx - hd_len - 1);
734:
735: } else {
736: char msg[80];
737: int padding = 30;
738: int max_cols;
739:
740: #ifdef HAVE_IPINFO
741: if (is_printii(ctl))
742: padding += get_iiwidth(ctl->ipinfo_no);
743: #endif
744: max_cols =
745: maxx <= SAVED_PINGS + padding ? maxx - padding : SAVED_PINGS;
746: startstat = padding - 2;
747:
748: snprintf(msg, sizeof(msg), " Last %3d pings", max_cols);
749: mvprintw(rowstat - 1, startstat, msg);
750:
751: attroff(A_BOLD);
752: move(rowstat, 0);
753:
754: mtr_gen_scale(ctl);
755: mtr_curses_graph(ctl, startstat, max_cols);
756:
757: printw("\n");
758: attron(A_BOLD);
759: printw("Scale:");
760: attroff(A_BOLD);
761:
762: for (i = 0; i < NUM_FACTORS - 1; i++) {
763: printw(" ");
764: attrset(block_col[i + 1]);
765: printw("%c", block_map[i]);
766: attrset(A_NORMAL);
767: printw(":%d ms", scale[i] / 1000);
768: }
769: printw(" ");
770: attrset(block_col[NUM_FACTORS]);
771: printw("%c", block_map[NUM_FACTORS - 1]);
772: attrset(A_NORMAL);
773: }
774:
775: refresh();
776: }
777:
778:
779: void mtr_curses_open(
780: struct mtr_ctl *ctl)
781: {
782: int bg_col = 0;
783: int i;
784:
785: initscr();
786: raw();
787: noecho();
788: start_color();
789: if (use_default_colors() == OK)
790: bg_col = -1;
791: for (i = 0; i < NUM_FACTORS; i++)
792: init_pair(i + 1, i, bg_col);
793:
794: mtr_curses_init();
795: mtr_curses_redraw(ctl);
796: }
797:
798:
799: void mtr_curses_close(
800: void)
801: {
802: printw("\n");
803: endwin();
804: }
805:
806:
807: void mtr_curses_clear(
808: struct mtr_ctl *ctl)
809: {
810: mtr_curses_close();
811: mtr_curses_open(ctl);
812: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>