xref: /openbsd-src/usr.bin/systat/engine.c (revision e99dc071d52b29c534cbbe629dd4cb8df5c0bdf3)
1*e99dc071Stb /* $OpenBSD: engine.c,v 1.30 2023/10/10 09:30:06 tb Exp $	 */
273baed14Scanacar /*
373baed14Scanacar  * Copyright (c) 2001, 2007 Can Erkin Acar <canacar@openbsd.org>
473baed14Scanacar  *
573baed14Scanacar  * Permission to use, copy, modify, and distribute this software for any
673baed14Scanacar  * purpose with or without fee is hereby granted, provided that the above
773baed14Scanacar  * copyright notice and this permission notice appear in all copies.
873baed14Scanacar  *
973baed14Scanacar  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1073baed14Scanacar  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1173baed14Scanacar  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1273baed14Scanacar  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1373baed14Scanacar  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1473baed14Scanacar  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1573baed14Scanacar  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1673baed14Scanacar  */
1773baed14Scanacar 
1873baed14Scanacar 
192942b3ebSchl #include <sys/ioctl.h>
2073baed14Scanacar #include <sys/types.h>
2173baed14Scanacar #include <sys/queue.h>
2273baed14Scanacar 
2373baed14Scanacar #include <ctype.h>
2473baed14Scanacar #include <curses.h>
2573baed14Scanacar #include <signal.h>
2673baed14Scanacar #include <stdlib.h>
2773baed14Scanacar #include <string.h>
28c2688696Scanacar #include <term.h>
2973baed14Scanacar #include <unistd.h>
3007a32fc5Smillert #include <math.h>
31fcad183eSlum #include <err.h>
3273baed14Scanacar 
33c2688696Scanacar /* XXX These are defined in term.h and conflict with our variable names */
34c2688696Scanacar #ifdef columns
35c2688696Scanacar #undef columns
36c2688696Scanacar #endif
37c2688696Scanacar 
38c2688696Scanacar #ifdef lines
39c2688696Scanacar #undef lines
40c2688696Scanacar #endif
41c2688696Scanacar 
4273baed14Scanacar #include "engine.h"
4373baed14Scanacar 
44bc249449Sderaadt #define MINIMUM(a, b) (((a) < (b)) ? (a) : (b))
4573baed14Scanacar 
4673baed14Scanacar /* circular linked list of views */
47e0cad388Skrw TAILQ_HEAD(view_list, view_ent) view_head =
48e0cad388Skrw 				  TAILQ_HEAD_INITIALIZER(view_head);
4973baed14Scanacar struct view_ent {
5073baed14Scanacar 	field_view *view;
51e0cad388Skrw 	TAILQ_ENTRY(view_ent) entries;
5273baed14Scanacar };
5373baed14Scanacar 
5407a32fc5Smillert static struct timespec ts_delay = { 5, 0 };
5507a32fc5Smillert static struct itimerval it_delay = { { 0, 0 }, { 5, 0 } };
5607a32fc5Smillert 
5773baed14Scanacar int dispstart = 0;
58ca743186Smartijn int humanreadable = 0;
5973baed14Scanacar int interactive = 1;
60c7d45d65Sreyk int averageonly = 0;
6173baed14Scanacar int maxprint = 0;
6273baed14Scanacar int paused = 0;
6373baed14Scanacar int rawmode = 0;
6473baed14Scanacar int rawwidth = DEFAULT_WIDTH;
6573baed14Scanacar int sortdir = 1;
6673baed14Scanacar int columns, lines;
6773baed14Scanacar u_int32_t num_disp = 0;
6873baed14Scanacar int max_disp = -1;
6973baed14Scanacar 
7073baed14Scanacar volatile sig_atomic_t gotsig_close = 0;
7173baed14Scanacar volatile sig_atomic_t gotsig_resize = 0;
7273baed14Scanacar volatile sig_atomic_t gotsig_alarm = 0;
7373baed14Scanacar int need_update = 0;
7473baed14Scanacar int need_sort = 0;
755c280c62Smpf int separate_thousands = 0;
7673baed14Scanacar 
7773baed14Scanacar SCREEN *screen;
7873baed14Scanacar 
7973baed14Scanacar field_view *curr_view = NULL;
8073baed14Scanacar struct view_ent *curr_view_ent = NULL;
8173baed14Scanacar struct view_manager *curr_mgr = NULL;
8273baed14Scanacar 
8373baed14Scanacar int curr_line = 0;
8473baed14Scanacar int home_line = 0;
8573baed14Scanacar 
8673baed14Scanacar /* line buffer for raw mode */
8773baed14Scanacar char linebuf[MAX_LINE_BUF];
8873baed14Scanacar int linepos = 0;
8973baed14Scanacar 
9073baed14Scanacar /* temp storage for state printing */
9173baed14Scanacar char tmp_buf[MAX_LINE_BUF];
9273baed14Scanacar 
9373baed14Scanacar char cmdbuf[MAX_LINE_BUF];
9473baed14Scanacar int cmd_len = -1;
9573baed14Scanacar struct command *curr_cmd = NULL;
9673baed14Scanacar char *curr_message = NULL;
97d539d1daSmartijn enum message_mode message_mode = MESSAGE_NONE;
98d539d1daSmartijn int message_cont = 1;
9973baed14Scanacar 
10073baed14Scanacar void print_cmdline(void);
10173baed14Scanacar 
10273baed14Scanacar 
10373baed14Scanacar /* screen output functions */
10473baed14Scanacar 
10573baed14Scanacar char * tb_ptr = NULL;
10673baed14Scanacar int tb_len = 0;
10773baed14Scanacar 
10873baed14Scanacar void
tb_start(void)10973baed14Scanacar tb_start(void)
11073baed14Scanacar {
11173baed14Scanacar 	tb_ptr = tmp_buf;
11273baed14Scanacar 	tb_len = sizeof(tmp_buf);
11373baed14Scanacar 	tb_ptr[0] = '\0';
11473baed14Scanacar }
11573baed14Scanacar 
11673baed14Scanacar void
tb_end(void)11773baed14Scanacar tb_end(void)
11873baed14Scanacar {
11973baed14Scanacar 	tb_ptr = NULL;
12073baed14Scanacar 	tb_len = 0;
12173baed14Scanacar }
12273baed14Scanacar 
12373baed14Scanacar int
tbprintf(char * format,...)12473baed14Scanacar tbprintf(char *format, ...)
12573baed14Scanacar {
12673baed14Scanacar 	int len;
12773baed14Scanacar 	va_list arg;
12873baed14Scanacar 
12973baed14Scanacar 	if (tb_ptr == NULL || tb_len <= 0)
13073baed14Scanacar 		return 0;
13173baed14Scanacar 
13273baed14Scanacar 	va_start(arg, format);
13373baed14Scanacar 	len = vsnprintf(tb_ptr, tb_len, format, arg);
13473baed14Scanacar 	va_end(arg);
13573baed14Scanacar 
13673baed14Scanacar 	if (len > tb_len)
13773baed14Scanacar 		tb_end();
13873baed14Scanacar 	else if (len > 0) {
13973baed14Scanacar 		tb_ptr += len;
14073baed14Scanacar 		tb_len -= len;
14173baed14Scanacar 	}
14273baed14Scanacar 
14373baed14Scanacar 	return len;
14473baed14Scanacar }
14573baed14Scanacar 
1465c280c62Smpf int
tbprintft(char * format,...)1475c280c62Smpf tbprintft(char *format, ...)
1485c280c62Smpf {
1495c280c62Smpf 	int len;
1505c280c62Smpf 	va_list arg;
1515c280c62Smpf 	char buf[MAX_LINE_BUF];
1525c280c62Smpf 
1535c280c62Smpf 	if (tb_ptr == NULL || tb_len <= 0)
1545c280c62Smpf 		return 0;
1555c280c62Smpf 
1565c280c62Smpf 	va_start(arg, format);
1575c280c62Smpf 	len = vsnprintf(buf, tb_len, format, arg);
1585c280c62Smpf 	va_end(arg);
1595c280c62Smpf 
1605c280c62Smpf 	if (len > tb_len)
1615c280c62Smpf 		tb_end();
1625c280c62Smpf 	else if (len > 0) {
1635c280c62Smpf 		int d, s;
1645c280c62Smpf 		int digits, curdigit;
1655c280c62Smpf 
1665c280c62Smpf 		if (!separate_thousands) {
1675c280c62Smpf 			strlcpy(tb_ptr, buf, tb_len);
1685c280c62Smpf 			return len;
1695c280c62Smpf 		}
1705c280c62Smpf 
1715c280c62Smpf 		/* count until we hit a non digit. (e.g. the prefix) */
1725c280c62Smpf 		for (digits = 0; digits < len; digits++)
17328ce9ad7Sderaadt 			if (!isdigit((unsigned char)buf[digits]))
1745c280c62Smpf 				break;
1755c280c62Smpf 
1765c280c62Smpf 		curdigit = digits;
1775c280c62Smpf 		d = s = 0;
1785c280c62Smpf 		/* insert thousands separators while copying */
1795c280c62Smpf 		while (curdigit && d < tb_len) {
1805c280c62Smpf 			if (curdigit < digits && curdigit % 3 == 0)
1815c280c62Smpf 				tb_ptr[d++] = ',';
1825c280c62Smpf 			tb_ptr[d++] = buf[s++];
1835c280c62Smpf 			curdigit--;
1845c280c62Smpf 		}
1855c280c62Smpf 		/* copy the remaining non-digits */
1865c280c62Smpf 		while (len > digits && d < tb_len) {
1875c280c62Smpf 			tb_ptr[d++] = buf[s++];
1885c280c62Smpf 			digits++;
1895c280c62Smpf 		}
1905c280c62Smpf 		tb_ptr[d] = '\0';
1915c280c62Smpf 		tb_ptr += d;
1925c280c62Smpf 		tb_len -= d;
1935c280c62Smpf 		len = d;
1945c280c62Smpf 	}
1955c280c62Smpf 	return len;
1965c280c62Smpf }
1975c280c62Smpf 
19873baed14Scanacar void
move_horiz(int offset)19973baed14Scanacar move_horiz(int offset)
20073baed14Scanacar {
20173baed14Scanacar 	if (rawmode) {
20273baed14Scanacar 		if (offset <= 0)
20373baed14Scanacar 			linepos = 0;
20473baed14Scanacar 		else if (offset >= MAX_LINE_BUF)
20573baed14Scanacar 			linepos = MAX_LINE_BUF - 1;
20673baed14Scanacar 		else
20773baed14Scanacar 			linepos = offset;
20873baed14Scanacar 	} else {
20973baed14Scanacar 		move(curr_line, offset);
21073baed14Scanacar 	}
21173baed14Scanacar }
21273baed14Scanacar 
21373baed14Scanacar void
print_str(int len,const char * str)21473baed14Scanacar print_str(int len, const char *str)
21573baed14Scanacar {
21673baed14Scanacar 	if (len <= 0)
21773baed14Scanacar 		return;
21873baed14Scanacar 
21973baed14Scanacar 	if (rawmode) {
220bc249449Sderaadt 		int length = MINIMUM(len, MAX_LINE_BUF - linepos);
22173baed14Scanacar 		if (length <= 0)
22273baed14Scanacar 			return;
22373baed14Scanacar 		bcopy(str, &linebuf[linepos], length);
22473baed14Scanacar 		linepos += length;
22573baed14Scanacar 	} else
22673baed14Scanacar 		addnstr(str, len);
22773baed14Scanacar }
22873baed14Scanacar 
22973baed14Scanacar void
clear_linebuf(void)23073baed14Scanacar clear_linebuf(void)
23173baed14Scanacar {
23273baed14Scanacar 	memset(linebuf, ' ', MAX_LINE_BUF);
23373baed14Scanacar }
23473baed14Scanacar 
23573baed14Scanacar void
end_line(void)23673baed14Scanacar end_line(void)
23773baed14Scanacar {
23873baed14Scanacar 	if (rawmode) {
23973baed14Scanacar 		linebuf[rawwidth] = '\0';
24073baed14Scanacar 		printf("%s\n", linebuf);
24173baed14Scanacar 		clear_linebuf();
24273baed14Scanacar 	}
24373baed14Scanacar 	curr_line++;
24473baed14Scanacar }
24573baed14Scanacar 
24673baed14Scanacar void
end_page(void)24773baed14Scanacar end_page(void)
24873baed14Scanacar {
24973baed14Scanacar 	if (rawmode) {
25073baed14Scanacar 		linepos = 0;
25173baed14Scanacar 		clear_linebuf();
252505a14acSsolene 		fflush(stdout);
25373baed14Scanacar 	} else {
25473baed14Scanacar 		move(home_line, 0);
25573baed14Scanacar 		print_cmdline();
25673baed14Scanacar 		refresh();
25773baed14Scanacar 	}
25873baed14Scanacar 	curr_line = 0;
25973baed14Scanacar }
26073baed14Scanacar 
26173baed14Scanacar /* field output functions */
26273baed14Scanacar 
26373baed14Scanacar void
print_fld_str(field_def * fld,const char * str)26473baed14Scanacar print_fld_str(field_def *fld, const char *str)
26573baed14Scanacar {
26607fe0f2dScanacar 	int len, offset;
26773baed14Scanacar 	char *cpos;
26873baed14Scanacar 
26973baed14Scanacar 	if (str == NULL || fld == NULL)
27073baed14Scanacar 		return;
27173baed14Scanacar 
27273baed14Scanacar 	if (fld->start < 0)
27373baed14Scanacar 		return;
27473baed14Scanacar 
27573baed14Scanacar 	len = strlen(str);
27673baed14Scanacar 
27773baed14Scanacar 	if (len >= fld->width) {
27873baed14Scanacar 		move_horiz(fld->start);
27973baed14Scanacar 		print_str(fld->width, str);
28073baed14Scanacar 	} else {
28173baed14Scanacar 		switch (fld->align) {
28273baed14Scanacar 		case FLD_ALIGN_RIGHT:
28373baed14Scanacar 			move_horiz(fld->start + (fld->width - len));
28473baed14Scanacar 			break;
28573baed14Scanacar 		case FLD_ALIGN_CENTER:
28673baed14Scanacar 			move_horiz(fld->start + (fld->width - len) / 2);
28773baed14Scanacar 			break;
28873baed14Scanacar 		case FLD_ALIGN_COLUMN:
28973baed14Scanacar 			if ((cpos = strchr(str, ':')) == NULL) {
29007fe0f2dScanacar 				offset = (fld->width - len) / 2;
29173baed14Scanacar 			} else {
29207fe0f2dScanacar 				offset = (fld->width / 2) - (cpos - str);
29307fe0f2dScanacar 				if (offset < 0)
29407fe0f2dScanacar 					offset = 0;
29507fe0f2dScanacar 				else if (offset > (fld->width - len))
29607fe0f2dScanacar 					offset = fld->width - len;
29773baed14Scanacar 			}
29807fe0f2dScanacar 			move_horiz(fld->start + offset);
29973baed14Scanacar 			break;
30073baed14Scanacar 		default:
30173baed14Scanacar 			move_horiz(fld->start);
30273baed14Scanacar 			break;
30373baed14Scanacar 		}
30473baed14Scanacar 		print_str(len, str);
30573baed14Scanacar 	}
30673baed14Scanacar }
30773baed14Scanacar 
30873baed14Scanacar void
print_bar_title(field_def * fld)30973baed14Scanacar print_bar_title(field_def *fld)
31073baed14Scanacar {
31173baed14Scanacar 	char buf[16];
31207fe0f2dScanacar 	int len, i, d, tr, tw, val, pos, cur;
31373baed14Scanacar 
31473baed14Scanacar 	int divs[] = {20, 10, 5, 4, 3, 2, 1, 0};
31573baed14Scanacar 
31673baed14Scanacar 	if (fld->width < 1)
31773baed14Scanacar 		return;
31873baed14Scanacar 
31973baed14Scanacar 	len = snprintf(buf, sizeof(buf), " %d\\", fld->arg);
32073baed14Scanacar 	if (len >= sizeof(buf))
32173baed14Scanacar 		return;
32273baed14Scanacar 
32373baed14Scanacar 	for (i = 0; divs[i]; i++)
32473baed14Scanacar 		if (divs[i] * len <= fld->width)
32573baed14Scanacar 			break;
32673baed14Scanacar 
32773baed14Scanacar 	if (divs[i] == 0) {
32873baed14Scanacar 		print_fld_str(fld, "*****");
32973baed14Scanacar 		return;
33073baed14Scanacar 	}
33173baed14Scanacar 
33207fe0f2dScanacar 	d = divs[i];
33373baed14Scanacar 
33473baed14Scanacar 	val = 0;
33573baed14Scanacar 	pos = 0;
33607fe0f2dScanacar 	tr = fld->arg % d;
33707fe0f2dScanacar 	tw = fld->width % d;
33873baed14Scanacar 
33973baed14Scanacar 	tb_start();
34073baed14Scanacar 	cur = 0;
34107fe0f2dScanacar 	for(i = 0; i < d; i++) {
34273baed14Scanacar 		tw += fld->width;
34373baed14Scanacar 		tr += fld->arg;
34473baed14Scanacar 
34507fe0f2dScanacar 		while (tr >= d) {
34673baed14Scanacar 			val++;
34707fe0f2dScanacar 			tr -= d;
34873baed14Scanacar 		}
34907fe0f2dScanacar 		while (tw >= d) {
35073baed14Scanacar 			pos++;
35107fe0f2dScanacar 			tw -= d;
35273baed14Scanacar 		}
35373baed14Scanacar 
35473baed14Scanacar 		len = snprintf(buf, sizeof(buf), "%d\\", val);
355807febabSderaadt 		if (len >= sizeof(buf))
356807febabSderaadt 			len = strlen(buf);
35773baed14Scanacar 		while (cur < pos - len) {
35873baed14Scanacar 			tbprintf(" ");
35973baed14Scanacar 			cur++;
36073baed14Scanacar 		}
36173baed14Scanacar 		tbprintf("%s", buf);
36273baed14Scanacar 		cur += len;
36373baed14Scanacar 	}
36473baed14Scanacar 
36573baed14Scanacar 	print_fld_tb(fld);
36673baed14Scanacar }
36773baed14Scanacar 
36873baed14Scanacar void
print_fld_bar(field_def * fld,int value)36973baed14Scanacar print_fld_bar(field_def *fld, int value)
37073baed14Scanacar {
37148556a4dSbenno 	int i, tw, val;
37273baed14Scanacar 
37373baed14Scanacar 	if (fld->width < 1)
37473baed14Scanacar 		return;
37573baed14Scanacar 
37673baed14Scanacar 	val = 0;
37773baed14Scanacar 	tw = fld->arg / 2;
37873baed14Scanacar 
37973baed14Scanacar 	tb_start();
38048556a4dSbenno 
38173baed14Scanacar 	for(i = 0; i < fld->width; i++) {
38273baed14Scanacar 		tw += fld->arg;
38373baed14Scanacar 
38473baed14Scanacar 		while (tw >= fld->width) {
38573baed14Scanacar 			val++;
38673baed14Scanacar 			tw -= fld->width;
38773baed14Scanacar 		}
38873baed14Scanacar 		if (val > value)
38973baed14Scanacar 			break;
39073baed14Scanacar 		tbprintf("#");
39173baed14Scanacar 	}
39273baed14Scanacar 
39373baed14Scanacar 	print_fld_tb(fld);
39473baed14Scanacar }
39573baed14Scanacar 
39673baed14Scanacar void
print_fld_tb(field_def * fld)39773baed14Scanacar print_fld_tb(field_def *fld)
39873baed14Scanacar {
39973baed14Scanacar 	print_fld_str(fld, tmp_buf);
40073baed14Scanacar 	tb_end();
40173baed14Scanacar }
40273baed14Scanacar 
40373baed14Scanacar void
print_title(void)40473baed14Scanacar print_title(void)
40573baed14Scanacar {
40673baed14Scanacar 	field_def **fp;
40773baed14Scanacar 
40873baed14Scanacar 	if (curr_view != NULL && curr_view->view != NULL) {
40973baed14Scanacar 		for (fp = curr_view->view; *fp != NULL; fp++) {
41073baed14Scanacar 			switch((*fp)->align) {
41173baed14Scanacar 			case FLD_ALIGN_LEFT:
41273baed14Scanacar 			case FLD_ALIGN_RIGHT:
41373baed14Scanacar 			case FLD_ALIGN_CENTER:
41473baed14Scanacar 			case FLD_ALIGN_COLUMN:
41573baed14Scanacar 				print_fld_str(*fp, (*fp)->title);
41673baed14Scanacar 				break;
41773baed14Scanacar 			case FLD_ALIGN_BAR:
41873baed14Scanacar 				print_bar_title(*fp);
41973baed14Scanacar 				break;
42073baed14Scanacar 			}
42173baed14Scanacar 		}
42273baed14Scanacar 	}
42373baed14Scanacar 	end_line();
42473baed14Scanacar }
42573baed14Scanacar 
42673baed14Scanacar /* view related functions */
42773baed14Scanacar void
hide_field(field_def * fld)42873baed14Scanacar hide_field(field_def *fld)
42973baed14Scanacar {
43073baed14Scanacar 	if (fld == NULL)
43173baed14Scanacar 		return;
43273baed14Scanacar 
43373baed14Scanacar 	fld->flags |= FLD_FLAG_HIDDEN;
43473baed14Scanacar }
43573baed14Scanacar 
43673baed14Scanacar void
show_field(field_def * fld)43773baed14Scanacar show_field(field_def *fld)
43873baed14Scanacar {
43973baed14Scanacar 	if (fld == NULL)
44073baed14Scanacar 		return;
44173baed14Scanacar 
44273baed14Scanacar 	fld->flags &= ~((unsigned int) FLD_FLAG_HIDDEN);
44373baed14Scanacar }
44473baed14Scanacar 
44573baed14Scanacar void
reset_fields(void)44673baed14Scanacar reset_fields(void)
44773baed14Scanacar {
44873baed14Scanacar 	field_def **fp;
44973baed14Scanacar 	field_def *fld;
45073baed14Scanacar 
45173baed14Scanacar 	if (curr_view == NULL)
45273baed14Scanacar 		return;
45373baed14Scanacar 
45473baed14Scanacar 	if (curr_view->view == NULL)
45573baed14Scanacar 		return;
45673baed14Scanacar 
45773baed14Scanacar 	for (fp = curr_view->view; *fp != NULL; fp++) {
45873baed14Scanacar 		fld = *fp;
45973baed14Scanacar 		fld->start = -1;
46073baed14Scanacar 		fld->width = fld->norm_width;
46173baed14Scanacar 	}
46273baed14Scanacar }
46373baed14Scanacar 
46473baed14Scanacar void
field_setup(void)46573baed14Scanacar field_setup(void)
46673baed14Scanacar {
46773baed14Scanacar 	field_def **fp;
46873baed14Scanacar 	field_def *fld;
46973baed14Scanacar 	int st, fwid, change;
47073baed14Scanacar 	int width = columns;
47173baed14Scanacar 
47273baed14Scanacar 	reset_fields();
47373baed14Scanacar 
47473baed14Scanacar 	dispstart = 0;
47573baed14Scanacar 	st = 0;
47673baed14Scanacar 
47773baed14Scanacar 	for (fp = curr_view->view; *fp != NULL; fp++) {
47873baed14Scanacar 		fld = *fp;
47973baed14Scanacar 		if (fld->flags & FLD_FLAG_HIDDEN)
48073baed14Scanacar 			continue;
48173baed14Scanacar 
48273baed14Scanacar 		if (width <= 1)
48373baed14Scanacar 			break;
48473baed14Scanacar 
48573baed14Scanacar 		if (st != 1)
48673baed14Scanacar 			width--;
48773baed14Scanacar 
48873baed14Scanacar 		fld->start = 1;
48973baed14Scanacar 		fwid = fld->width;
49073baed14Scanacar 		st++;
49173baed14Scanacar 		if (fwid >= width) {
49273baed14Scanacar 			fld->width = width;
49373baed14Scanacar 			width = 0;
49473baed14Scanacar 		} else
49573baed14Scanacar 			width -= fwid;
49673baed14Scanacar 	}
49773baed14Scanacar 
49873baed14Scanacar 	while (width > 0) {
49973baed14Scanacar 		change = 0;
50073baed14Scanacar 		for (fp = curr_view->view; *fp != NULL; fp++) {
50173baed14Scanacar 			fld = *fp;
50273baed14Scanacar 			if (fld->flags & FLD_FLAG_HIDDEN)
50373baed14Scanacar 				continue;
50473baed14Scanacar 			if ((fld->width < fld->max_width) &&
50573baed14Scanacar 			    (fld->increment <= width)) {
50673baed14Scanacar 				int w = fld->width + fld->increment;
50773baed14Scanacar 				if (w > fld->max_width)
50873baed14Scanacar 					w = fld->max_width;
50973baed14Scanacar 				width += fld->width - w;
51073baed14Scanacar 				fld->width = w;
51173baed14Scanacar 				change = 1;
51273baed14Scanacar 			}
51373baed14Scanacar 			if (width <= 0) break;
51473baed14Scanacar 		}
51573baed14Scanacar 		if (change == 0) break;
51673baed14Scanacar 	}
51773baed14Scanacar 
51873baed14Scanacar 	st = 0;
51973baed14Scanacar 	for (fp = curr_view->view; *fp != NULL; fp++) {
52073baed14Scanacar 		fld = *fp;
52173baed14Scanacar 		if (fld->flags & FLD_FLAG_HIDDEN)
52273baed14Scanacar 			continue;
52373baed14Scanacar 		if (fld->start < 0) break;
52473baed14Scanacar 		fld->start = st;
52573baed14Scanacar 		st += fld->width + 1;
52673baed14Scanacar 	}
52773baed14Scanacar }
52873baed14Scanacar 
52973baed14Scanacar void
set_curr_view(struct view_ent * ve)53073baed14Scanacar set_curr_view(struct view_ent *ve)
53173baed14Scanacar {
53273baed14Scanacar 	field_view *v;
53373baed14Scanacar 
53473baed14Scanacar 	reset_fields();
53573baed14Scanacar 
53673baed14Scanacar 	if (ve == NULL) {
53773baed14Scanacar 		curr_view_ent = NULL;
53873baed14Scanacar 		curr_view = NULL;
53973baed14Scanacar 		curr_mgr = NULL;
54073baed14Scanacar 		return;
54173baed14Scanacar 	}
54273baed14Scanacar 
54373baed14Scanacar 	v = ve->view;
54473baed14Scanacar 
54573baed14Scanacar 	if ((curr_view != NULL) && (curr_mgr != v->mgr)) {
54673baed14Scanacar 		gotsig_alarm = 1;
54773baed14Scanacar 		if (v->mgr != NULL && v->mgr->select_fn != NULL)
54873baed14Scanacar 			v->mgr->select_fn();
54973baed14Scanacar 	}
55073baed14Scanacar 
55173baed14Scanacar 	curr_view_ent = ve;
55273baed14Scanacar 	curr_view = v;
55373baed14Scanacar 	curr_mgr = v->mgr;
55473baed14Scanacar 	field_setup();
55573baed14Scanacar 	need_update = 1;
55673baed14Scanacar }
55773baed14Scanacar 
55873baed14Scanacar void
add_view(field_view * fv)55973baed14Scanacar add_view(field_view *fv)
56073baed14Scanacar {
56173baed14Scanacar 	struct view_ent *ent;
56273baed14Scanacar 
56373baed14Scanacar 	if (fv == NULL)
56473baed14Scanacar 		return;
56573baed14Scanacar 
56673baed14Scanacar 	if (fv->view == NULL || fv->name == NULL || fv->mgr == NULL)
56773baed14Scanacar 		return;
56873baed14Scanacar 
56973baed14Scanacar 	ent = malloc(sizeof(struct view_ent));
57073baed14Scanacar 	if (ent == NULL)
57173baed14Scanacar 		return;
57273baed14Scanacar 
57373baed14Scanacar 	ent->view = fv;
574e0cad388Skrw 	TAILQ_INSERT_TAIL(&view_head, ent, entries);
57573baed14Scanacar 
57673baed14Scanacar 	if (curr_view == NULL)
57773baed14Scanacar 		set_curr_view(ent);
57873baed14Scanacar }
57973baed14Scanacar 
58073baed14Scanacar int
set_view(const char * opt)5813185e9c1Scanacar set_view(const char *opt)
58273baed14Scanacar {
58373baed14Scanacar 	struct view_ent *ve, *vm = NULL;
58473baed14Scanacar 	field_view *v;
58573baed14Scanacar 	int len;
58673baed14Scanacar 
58773baed14Scanacar 	if (opt == NULL || (len = strlen(opt)) == 0)
58873baed14Scanacar 		return 1;
58973baed14Scanacar 
590e0cad388Skrw 	TAILQ_FOREACH(ve, &view_head, entries) {
59173baed14Scanacar 		v = ve->view;
59273baed14Scanacar 		if (strncasecmp(opt, v->name, len) == 0) {
59373baed14Scanacar 			if (vm)
59473baed14Scanacar 				return 1;
59573baed14Scanacar 			vm = ve;
59673baed14Scanacar 		}
59773baed14Scanacar 	}
59873baed14Scanacar 
59973baed14Scanacar 	if (vm) {
60073baed14Scanacar 		set_curr_view(vm);
60173baed14Scanacar 		return 0;
60273baed14Scanacar 	}
60373baed14Scanacar 
60473baed14Scanacar 	return 1;
60573baed14Scanacar }
60673baed14Scanacar 
60773baed14Scanacar void
foreach_view(void (* callback)(field_view *))60873baed14Scanacar foreach_view(void (*callback)(field_view *))
60973baed14Scanacar {
61073baed14Scanacar 	struct view_ent *ve;
61173baed14Scanacar 
612e0cad388Skrw 	TAILQ_FOREACH(ve, &view_head, entries) {
61373baed14Scanacar 		callback(ve->view);
61473baed14Scanacar 	}
61573baed14Scanacar }
61673baed14Scanacar 
61773baed14Scanacar int
set_view_hotkey(int ch)61873baed14Scanacar set_view_hotkey(int ch)
61973baed14Scanacar {
62073baed14Scanacar 	struct view_ent *ve;
62173baed14Scanacar 	field_view *v;
62273baed14Scanacar 	int key = tolower(ch);
62373baed14Scanacar 
624e0cad388Skrw 	TAILQ_FOREACH(ve, &view_head, entries) {
62573baed14Scanacar 		v = ve->view;
62673baed14Scanacar 		if (key == v->hotkey) {
62773baed14Scanacar 			set_curr_view(ve);
62873baed14Scanacar 			return 1;
62973baed14Scanacar 		}
63073baed14Scanacar 	}
63173baed14Scanacar 
63273baed14Scanacar 	return 0;
63373baed14Scanacar }
63473baed14Scanacar 
63573baed14Scanacar void
next_view(void)63673baed14Scanacar next_view(void)
63773baed14Scanacar {
63873baed14Scanacar 	struct view_ent *ve;
63973baed14Scanacar 
640e0cad388Skrw 	if (TAILQ_EMPTY(&view_head) || curr_view_ent == NULL)
64173baed14Scanacar 		return;
64273baed14Scanacar 
643e0cad388Skrw 	ve = TAILQ_NEXT(curr_view_ent, entries);
644e0cad388Skrw 	if (ve == NULL)
645e0cad388Skrw 		ve = TAILQ_FIRST(&view_head);
64673baed14Scanacar 
64773baed14Scanacar 	set_curr_view(ve);
64873baed14Scanacar }
64973baed14Scanacar 
65073baed14Scanacar void
prev_view(void)65173baed14Scanacar prev_view(void)
65273baed14Scanacar {
65373baed14Scanacar 	struct view_ent *ve;
65473baed14Scanacar 
655e0cad388Skrw 	if (TAILQ_EMPTY(&view_head) || curr_view_ent == NULL)
65673baed14Scanacar 		return;
65773baed14Scanacar 
658e0cad388Skrw 	ve = TAILQ_PREV(curr_view_ent, view_list, entries);
659e0cad388Skrw 	if (ve == NULL)
660e0cad388Skrw 		ve = TAILQ_LAST(&view_head, view_list);
66173baed14Scanacar 
66273baed14Scanacar 	set_curr_view(ve);
66373baed14Scanacar }
66473baed14Scanacar 
66573baed14Scanacar /* generic field printing */
66673baed14Scanacar 
66773baed14Scanacar void
print_fld_age(field_def * fld,unsigned int age)66873baed14Scanacar print_fld_age(field_def *fld, unsigned int age)
66973baed14Scanacar {
67073baed14Scanacar 	int len;
67173baed14Scanacar 	unsigned int h, m, s;
67273baed14Scanacar 
67373baed14Scanacar 	if (fld == NULL)
67473baed14Scanacar 		return;
67573baed14Scanacar 	len = fld->width;
67673baed14Scanacar 
67773baed14Scanacar 	if (len < 1)
67873baed14Scanacar 		return;
67973baed14Scanacar 
68073baed14Scanacar 	s = age % 60;
68173baed14Scanacar 	m = age / 60;
68273baed14Scanacar 	h = m / 60;
68373baed14Scanacar 	m %= 60;
68473baed14Scanacar 
68573baed14Scanacar 	tb_start();
68673baed14Scanacar 	if (tbprintf("%02u:%02u:%02u", h, m, s) <= len)
68773baed14Scanacar 		goto ok;
68873baed14Scanacar 
68953852b85Scanacar 	tb_start();
69073baed14Scanacar 	if (tbprintf("%u", age) <= len)
69173baed14Scanacar 		goto ok;
69273baed14Scanacar 
69353852b85Scanacar 	tb_start();
69473baed14Scanacar 	age /= 60;
69573baed14Scanacar 	if (tbprintf("%um", age) <= len)
69673baed14Scanacar 		goto ok;
69773baed14Scanacar 	if (age == 0)
69873baed14Scanacar 		goto err;
69973baed14Scanacar 
70053852b85Scanacar 	tb_start();
70173baed14Scanacar 	age /= 60;
70273baed14Scanacar 	if (tbprintf("%uh", age) <= len)
70373baed14Scanacar 		goto ok;
70473baed14Scanacar 	if (age == 0)
70573baed14Scanacar 		goto err;
70673baed14Scanacar 
70753852b85Scanacar 	tb_start();
70873baed14Scanacar 	age /= 24;
70973baed14Scanacar 	if (tbprintf("%ud", age) <= len)
71073baed14Scanacar 		goto ok;
71173baed14Scanacar 
71273baed14Scanacar err:
71373baed14Scanacar 	print_fld_str(fld, "*");
71473baed14Scanacar 	tb_end();
71573baed14Scanacar 	return;
71673baed14Scanacar 
71773baed14Scanacar ok:
71873baed14Scanacar 	print_fld_tb(fld);
71973baed14Scanacar }
72073baed14Scanacar 
72173baed14Scanacar void
print_fld_sdiv(field_def * fld,u_int64_t size,int d)72207fe0f2dScanacar print_fld_sdiv(field_def *fld, u_int64_t size, int d)
72373baed14Scanacar {
72473baed14Scanacar 	int len;
725ca743186Smartijn 	char *mult = "KMGTPE";
726ca743186Smartijn 	int i = -1;
72773baed14Scanacar 
72873baed14Scanacar 	if (fld == NULL)
72973baed14Scanacar 		return;
73073baed14Scanacar 
73173baed14Scanacar 	len = fld->width;
73273baed14Scanacar 	if (len < 1)
73373baed14Scanacar 		return;
73473baed14Scanacar 
735ca743186Smartijn 	if (humanreadable) {
736ca743186Smartijn 		while (size >= 10000 && sizeof(mult) >= i + 1) {
737ca743186Smartijn 			i++;
73807fe0f2dScanacar 			size /= d;
739ca743186Smartijn 		}
740ca743186Smartijn 		tb_start();
741ca743186Smartijn 		if (tbprintft("%llu%.1s", size, i == -1 ? "" : mult + i) <= len)
74273baed14Scanacar 			goto ok;
74373baed14Scanacar 		goto err;
744ca743186Smartijn 	}
745ca743186Smartijn 	do {
74653852b85Scanacar 		tb_start();
747ca743186Smartijn 		if (tbprintft("%llu%.1s", size, i == -1 ? "" : mult + i) <= len)
74873baed14Scanacar 			goto ok;
749ca743186Smartijn 		i++;
75007fe0f2dScanacar 		size /= d;
751ca743186Smartijn 	} while (size != 0 && sizeof(mult) >= i);
75273baed14Scanacar err:
753ca743186Smartijn 	tb_start();
75473baed14Scanacar 	print_fld_str(fld, "*");
75573baed14Scanacar 	tb_end();
75673baed14Scanacar 	return;
75773baed14Scanacar 
75873baed14Scanacar ok:
75973baed14Scanacar 	print_fld_tb(fld);
76073baed14Scanacar }
76173baed14Scanacar 
76273baed14Scanacar void
print_fld_size(field_def * fld,u_int64_t size)76373baed14Scanacar print_fld_size(field_def *fld, u_int64_t size)
76473baed14Scanacar {
76573baed14Scanacar 	print_fld_sdiv(fld, size, 1024);
76673baed14Scanacar }
76773baed14Scanacar 
76873baed14Scanacar void
print_fld_ssdiv(field_def * fld,int64_t size,int d)76907fe0f2dScanacar print_fld_ssdiv(field_def *fld, int64_t size, int d)
7707d8d30a0Scanacar {
7717d8d30a0Scanacar 	int len;
7727d8d30a0Scanacar 
7737d8d30a0Scanacar 	if (fld == NULL)
7747d8d30a0Scanacar 		return;
7757d8d30a0Scanacar 
7767d8d30a0Scanacar 	len = fld->width;
7777d8d30a0Scanacar 	if (len < 1)
7787d8d30a0Scanacar 		return;
7797d8d30a0Scanacar 
7807d8d30a0Scanacar 	tb_start();
7815c280c62Smpf 	if (tbprintft("%lld", size) <= len)
7827d8d30a0Scanacar 		goto ok;
7837d8d30a0Scanacar 
7847d8d30a0Scanacar 	tb_start();
78507fe0f2dScanacar 	size /= d;
7865c280c62Smpf 	if (tbprintft("%lldK", size) <= len)
7877d8d30a0Scanacar 		goto ok;
7887d8d30a0Scanacar 	if (size == 0)
7897d8d30a0Scanacar 		goto err;
7907d8d30a0Scanacar 
7917d8d30a0Scanacar 	tb_start();
79207fe0f2dScanacar 	size /= d;
7935c280c62Smpf 	if (tbprintft("%lldM", size) <= len)
7947d8d30a0Scanacar 		goto ok;
7957d8d30a0Scanacar 	if (size == 0)
7967d8d30a0Scanacar 		goto err;
7977d8d30a0Scanacar 
7987d8d30a0Scanacar 	tb_start();
79907fe0f2dScanacar 	size /= d;
8005c280c62Smpf 	if (tbprintft("%lldG", size) <= len)
8017d8d30a0Scanacar 		goto ok;
8027d8d30a0Scanacar 	if (size == 0)
8037d8d30a0Scanacar 		goto err;
8047d8d30a0Scanacar 
8057d8d30a0Scanacar 	tb_start();
80607fe0f2dScanacar 	size /= d;
8075c280c62Smpf 	if (tbprintft("%lldT", size) <= len)
8087d8d30a0Scanacar 		goto ok;
8097d8d30a0Scanacar 
8107d8d30a0Scanacar err:
8117d8d30a0Scanacar 	print_fld_str(fld, "*");
8127d8d30a0Scanacar 	tb_end();
8137d8d30a0Scanacar 	return;
8147d8d30a0Scanacar 
8157d8d30a0Scanacar ok:
8167d8d30a0Scanacar 	print_fld_tb(fld);
8177d8d30a0Scanacar }
8187d8d30a0Scanacar 
8197d8d30a0Scanacar void
print_fld_ssize(field_def * fld,int64_t size)8207d8d30a0Scanacar print_fld_ssize(field_def *fld, int64_t size)
8217d8d30a0Scanacar {
8227d8d30a0Scanacar 	print_fld_ssdiv(fld, size, 1024);
8237d8d30a0Scanacar }
8247d8d30a0Scanacar 
8257d8d30a0Scanacar void
print_fld_rate(field_def * fld,double rate)82673baed14Scanacar print_fld_rate(field_def *fld, double rate)
82773baed14Scanacar {
82873baed14Scanacar 	if (rate < 0) {
82973baed14Scanacar 		print_fld_str(fld, "*");
83073baed14Scanacar 	} else {
83173baed14Scanacar 		print_fld_size(fld, rate);
83273baed14Scanacar 	}
83373baed14Scanacar }
83473baed14Scanacar 
83573baed14Scanacar void
print_fld_bw(field_def * fld,double bw)83673baed14Scanacar print_fld_bw(field_def *fld, double bw)
83773baed14Scanacar {
83873baed14Scanacar 	if (bw < 0) {
83973baed14Scanacar 		print_fld_str(fld, "*");
84073baed14Scanacar 	} else {
84173baed14Scanacar 		print_fld_sdiv(fld, bw, 1000);
84273baed14Scanacar 	}
84373baed14Scanacar }
84473baed14Scanacar 
84573baed14Scanacar void
print_fld_uint(field_def * fld,unsigned int size)84673baed14Scanacar print_fld_uint(field_def *fld, unsigned int size)
84773baed14Scanacar {
84873baed14Scanacar 	int len;
84973baed14Scanacar 
85073baed14Scanacar 	if (fld == NULL)
85173baed14Scanacar 		return;
85273baed14Scanacar 
85373baed14Scanacar 	len = fld->width;
85473baed14Scanacar 	if (len < 1)
85573baed14Scanacar 		return;
85673baed14Scanacar 
85773baed14Scanacar 	tb_start();
8585c280c62Smpf 	if (tbprintft("%u", size) > len)
85973baed14Scanacar 		print_fld_str(fld, "*");
86073baed14Scanacar 	else
86173baed14Scanacar 		print_fld_tb(fld);
86273baed14Scanacar 	tb_end();
86373baed14Scanacar }
86473baed14Scanacar 
865dfea33b3Snaddy void
print_fld_float(field_def * fld,double f,int prec)866dfea33b3Snaddy print_fld_float(field_def *fld, double f, int prec)
867dfea33b3Snaddy {
868dfea33b3Snaddy 	int len;
869dfea33b3Snaddy 
870dfea33b3Snaddy 	if (fld == NULL)
871dfea33b3Snaddy 		return;
872dfea33b3Snaddy 
873dfea33b3Snaddy 	len = fld->width;
874dfea33b3Snaddy 	if (len < 1)
875dfea33b3Snaddy 		return;
876dfea33b3Snaddy 
877dfea33b3Snaddy 	tb_start();
878dfea33b3Snaddy 	if (tbprintf("%*.*f", len, prec, f) > len)
879dfea33b3Snaddy 		print_fld_str(fld, "*");
880dfea33b3Snaddy 	else
881dfea33b3Snaddy 		print_fld_tb(fld);
882dfea33b3Snaddy 	tb_end();
883dfea33b3Snaddy }
884dfea33b3Snaddy 
88573baed14Scanacar 
88673baed14Scanacar /* ordering */
88773baed14Scanacar 
8888d6a960aSmartijn int
foreach_order(void (* callback)(order_type *))8898d6a960aSmartijn foreach_order(void (*callback)(order_type *))
8908d6a960aSmartijn {
8918d6a960aSmartijn 	order_type *o;
8928d6a960aSmartijn 
8938d6a960aSmartijn 	if (curr_view == NULL || curr_view->mgr == NULL ||
8948d6a960aSmartijn 	    curr_view->mgr->order_list == NULL)
8958d6a960aSmartijn 		return -1;
8968d6a960aSmartijn 	o = curr_view->mgr->order_list;
8978d6a960aSmartijn 	do {
8988d6a960aSmartijn 		callback(o++);
8998d6a960aSmartijn 	} while (o->name != NULL);
9008d6a960aSmartijn 	return 0;
9018d6a960aSmartijn }
9028d6a960aSmartijn 
90373baed14Scanacar void
set_order(const char * opt)9043185e9c1Scanacar set_order(const char *opt)
90573baed14Scanacar {
90673baed14Scanacar 	order_type *o;
90773baed14Scanacar 
90873baed14Scanacar 	if (curr_view == NULL || curr_view->mgr == NULL)
90973baed14Scanacar 		return;
91073baed14Scanacar 
91173baed14Scanacar 	curr_view->mgr->order_curr = curr_view->mgr->order_list;
91273baed14Scanacar 
91373baed14Scanacar 	if (opt == NULL)
91473baed14Scanacar 		return;
91573baed14Scanacar 
91673baed14Scanacar 	o = curr_view->mgr->order_list;
91773baed14Scanacar 
91873baed14Scanacar 	if (o == NULL)
91973baed14Scanacar 		return;
92073baed14Scanacar 
92173baed14Scanacar 	for (;o->name != NULL; o++) {
92273baed14Scanacar 		if (strcasecmp(opt, o->match) == 0) {
92373baed14Scanacar 			curr_view->mgr->order_curr = o;
92473baed14Scanacar 			return;
92573baed14Scanacar 		}
92673baed14Scanacar 	}
92773baed14Scanacar }
92873baed14Scanacar 
92973baed14Scanacar int
set_order_hotkey(int ch)93073baed14Scanacar set_order_hotkey(int ch)
93173baed14Scanacar {
93273baed14Scanacar 	order_type *o;
93373baed14Scanacar 	int key = ch;
93473baed14Scanacar 
93573baed14Scanacar 	if (curr_view == NULL || curr_view->mgr == NULL)
93673baed14Scanacar 		return 0;
93773baed14Scanacar 
93873baed14Scanacar 	o = curr_view->mgr->order_list;
93973baed14Scanacar 
94073baed14Scanacar 	if (o == NULL)
94173baed14Scanacar 		return 0;
94273baed14Scanacar 
94373baed14Scanacar 	for (;o->name != NULL; o++) {
94473baed14Scanacar 		if (key == o->hotkey) {
94573baed14Scanacar 			if (curr_view->mgr->order_curr == o) {
94673baed14Scanacar 				sortdir *= -1;
94773baed14Scanacar 			} else {
94873baed14Scanacar 				curr_view->mgr->order_curr = o;
94973baed14Scanacar 			}
95073baed14Scanacar 			return 1;
95173baed14Scanacar 		}
95273baed14Scanacar 	}
95373baed14Scanacar 
95473baed14Scanacar 	return 0;
95573baed14Scanacar }
95673baed14Scanacar 
95773baed14Scanacar void
next_order(void)95873baed14Scanacar next_order(void)
95973baed14Scanacar {
96073baed14Scanacar 	order_type *o, *oc;
96173baed14Scanacar 
962f3f02087Scanacar 	if (curr_view->mgr->order_list == NULL)
963f3f02087Scanacar 		return;
964f3f02087Scanacar 
96573baed14Scanacar 	oc = curr_view->mgr->order_curr;
96673baed14Scanacar 
96773baed14Scanacar 	for (o = curr_view->mgr->order_list; o->name != NULL; o++) {
96873baed14Scanacar 		if (oc == o) {
96973baed14Scanacar 			o++;
97073baed14Scanacar 			if (o->name == NULL)
97173baed14Scanacar 				break;
97273baed14Scanacar 			curr_view->mgr->order_curr = o;
97373baed14Scanacar 			return;
97473baed14Scanacar 		}
97573baed14Scanacar 	}
97673baed14Scanacar 
97773baed14Scanacar 	curr_view->mgr->order_curr = curr_view->mgr->order_list;
97873baed14Scanacar }
97973baed14Scanacar 
98073baed14Scanacar 
98173baed14Scanacar /* main program functions */
98273baed14Scanacar 
98373baed14Scanacar int
read_view(void)98473baed14Scanacar read_view(void)
98573baed14Scanacar {
98673baed14Scanacar 	if (curr_mgr == NULL)
98773baed14Scanacar 		return (0);
98873baed14Scanacar 
98973baed14Scanacar 	if (paused)
99073baed14Scanacar 		return (0);
99173baed14Scanacar 
99273baed14Scanacar 	if (curr_mgr->read_fn != NULL)
99373baed14Scanacar 		return (curr_mgr->read_fn());
99473baed14Scanacar 
99573baed14Scanacar 	return (0);
99673baed14Scanacar }
99773baed14Scanacar 
99873baed14Scanacar 
99973baed14Scanacar int
disp_update(void)100073baed14Scanacar disp_update(void)
100173baed14Scanacar {
100207fe0f2dScanacar 	int li;
100373baed14Scanacar 
100473baed14Scanacar 	if (maxprint < 0)
100573baed14Scanacar 		dispstart = 0;
100673baed14Scanacar 	else if (dispstart + maxprint > num_disp)
100773baed14Scanacar 		dispstart = num_disp - maxprint;
100873baed14Scanacar 
100973baed14Scanacar 	if (dispstart < 0)
101073baed14Scanacar 		dispstart = 0;
101173baed14Scanacar 
101273baed14Scanacar 	if (curr_view == NULL)
101373baed14Scanacar 		return 0;
101473baed14Scanacar 
101573baed14Scanacar 	if (curr_mgr != NULL) {
101673baed14Scanacar 		curr_line = 0;
101773baed14Scanacar 
101873baed14Scanacar 		if (curr_mgr->header_fn != NULL) {
101907fe0f2dScanacar 			li = curr_mgr->header_fn();
102007fe0f2dScanacar 			if (li < 0)
102173baed14Scanacar 				return (1);
102207fe0f2dScanacar 			curr_line = ++li;
102307fe0f2dScanacar 			home_line = li + maxprint + 1;
102473baed14Scanacar 		}
102573baed14Scanacar 
102673baed14Scanacar 		print_title();
102773baed14Scanacar 
102873baed14Scanacar 		if (curr_mgr->print_fn != NULL)
102973baed14Scanacar 			curr_mgr->print_fn();
103073baed14Scanacar 	}
103173baed14Scanacar 
103273baed14Scanacar 	return (0);
103373baed14Scanacar }
103473baed14Scanacar 
103573baed14Scanacar void
sort_view(void)103673baed14Scanacar sort_view(void)
103773baed14Scanacar {
103873baed14Scanacar 	if (curr_mgr != NULL)
103973baed14Scanacar 		if (curr_mgr->sort_fn != NULL)
104073baed14Scanacar 			curr_mgr->sort_fn();
104173baed14Scanacar }
104273baed14Scanacar 
104373baed14Scanacar void
sig_close(int sig)104407fe0f2dScanacar sig_close(int sig)
104573baed14Scanacar {
104673baed14Scanacar 	gotsig_close = 1;
104773baed14Scanacar }
104873baed14Scanacar 
104973baed14Scanacar void
sig_resize(int sig)105007fe0f2dScanacar sig_resize(int sig)
105173baed14Scanacar {
105273baed14Scanacar 	gotsig_resize = 1;
105373baed14Scanacar }
105473baed14Scanacar 
105573baed14Scanacar void
sig_alarm(int sig)105607fe0f2dScanacar sig_alarm(int sig)
105773baed14Scanacar {
105873baed14Scanacar 	gotsig_alarm = 1;
105973baed14Scanacar }
106073baed14Scanacar 
106173baed14Scanacar void
setup_term(int dmax)106273baed14Scanacar setup_term(int dmax)
106373baed14Scanacar {
106473baed14Scanacar 	max_disp = dmax;
106573baed14Scanacar 	maxprint = dmax;
106673baed14Scanacar 
106773baed14Scanacar 	if (rawmode) {
106873baed14Scanacar 		columns = rawwidth;
106973baed14Scanacar 		lines = DEFAULT_HEIGHT;
107073baed14Scanacar 		clear_linebuf();
107173baed14Scanacar 	} else {
107273baed14Scanacar 		if (dmax < 0)
107373baed14Scanacar 			dmax = 0;
107473baed14Scanacar 
107573baed14Scanacar 		screen = newterm(NULL, stdout, stdin);
107673baed14Scanacar 		if (screen == NULL) {
107773baed14Scanacar 			rawmode = 1;
107873baed14Scanacar 			interactive = 0;
107973baed14Scanacar 			setup_term(dmax);
108073baed14Scanacar 			return;
108173baed14Scanacar 		}
108273baed14Scanacar 		columns = COLS;
108373baed14Scanacar 		lines = LINES;
108473baed14Scanacar 
108573baed14Scanacar 		if (maxprint > lines - HEADER_LINES)
108673baed14Scanacar 			maxprint = lines - HEADER_LINES;
108773baed14Scanacar 
108873baed14Scanacar 		nonl();
108973baed14Scanacar 		keypad(stdscr, TRUE);
109073baed14Scanacar 		intrflush(stdscr, FALSE);
109173baed14Scanacar 
109273baed14Scanacar 		halfdelay(10);
109373baed14Scanacar 		noecho();
109473baed14Scanacar 	}
109573baed14Scanacar 
109673baed14Scanacar 	if (dmax == 0)
109773baed14Scanacar 		maxprint = lines - HEADER_LINES;
109873baed14Scanacar 
109973baed14Scanacar 	field_setup();
110073baed14Scanacar }
110173baed14Scanacar 
1102c2688696Scanacar void
do_resize_term(void)110381d8c4e1Snicm do_resize_term(void)
1104c2688696Scanacar {
1105c2688696Scanacar 	struct winsize ws;
1106c2688696Scanacar 
1107c2688696Scanacar 	if (rawmode)
1108c2688696Scanacar 		return;
1109c2688696Scanacar 
1110c2688696Scanacar 	if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) == -1)
1111c2688696Scanacar 		return;
1112c2688696Scanacar 
1113c2688696Scanacar 	resizeterm(ws.ws_row, ws.ws_col);
1114c2688696Scanacar 
1115c2688696Scanacar 	columns = COLS;
1116c2688696Scanacar 	lines = LINES;
1117c2688696Scanacar 
1118c2688696Scanacar 	maxprint = max_disp;
1119c2688696Scanacar 
1120c2688696Scanacar 	if (maxprint == 0 || maxprint > lines - HEADER_LINES)
1121c2688696Scanacar 		maxprint = lines - HEADER_LINES;
1122c2688696Scanacar 
1123c2688696Scanacar 	clear();
1124c2688696Scanacar 
1125c2688696Scanacar 	field_setup();
1126c2688696Scanacar }
1127c2688696Scanacar 
112873baed14Scanacar struct command *
command_set(struct command * cmd,const char * init)112973baed14Scanacar command_set(struct command *cmd, const char *init)
113073baed14Scanacar {
113173baed14Scanacar 	struct command *prev = curr_cmd;
113273baed14Scanacar 
113373baed14Scanacar 	if (cmd) {
113473baed14Scanacar 		if (init) {
113573baed14Scanacar 			cmd_len = strlcpy(cmdbuf, init, sizeof(cmdbuf));
113673baed14Scanacar 			if (cmd_len >= sizeof(cmdbuf)) {
113773baed14Scanacar 				cmdbuf[0] = '\0';
113873baed14Scanacar 				cmd_len = 0;
113973baed14Scanacar 			}
114073baed14Scanacar 		} else {
114173baed14Scanacar 			cmd_len = 0;
114273baed14Scanacar 			cmdbuf[0] = 0;
114373baed14Scanacar 		}
114473baed14Scanacar 	}
1145e9b50d6aStb 	message_set(NULL);
114673baed14Scanacar 	curr_cmd = cmd;
114773baed14Scanacar 	need_update = 1;
114873baed14Scanacar 	return prev;
114973baed14Scanacar }
115073baed14Scanacar 
1151d539d1daSmartijn void
message_toggle(enum message_mode mode)1152d539d1daSmartijn message_toggle(enum message_mode mode)
1153d539d1daSmartijn {
1154d539d1daSmartijn 	message_mode = message_mode != mode ? mode : MESSAGE_NONE;
1155d539d1daSmartijn 	need_update = 1;
1156d539d1daSmartijn 	message_cont = 1;
1157d539d1daSmartijn }
1158d539d1daSmartijn 
115973baed14Scanacar const char *
message_set(const char * msg)1160d539d1daSmartijn message_set(const char *msg)
1161d539d1daSmartijn {
1162d539d1daSmartijn 	free(curr_message);
1163d539d1daSmartijn 
1164d539d1daSmartijn 	if (msg) {
116573baed14Scanacar 		curr_message = strdup(msg);
1166d539d1daSmartijn 		message_cont = 0;
1167d539d1daSmartijn 	} else {
116873baed14Scanacar 		curr_message = NULL;
1169d539d1daSmartijn 		message_cont = 1;
1170d539d1daSmartijn 	}
117173baed14Scanacar 	return NULL;
117273baed14Scanacar }
117373baed14Scanacar 
117473baed14Scanacar void
print_cmdline(void)117573baed14Scanacar print_cmdline(void)
117673baed14Scanacar {
117773baed14Scanacar 	if (curr_cmd) {
117873baed14Scanacar 		attron(A_STANDOUT);
117973baed14Scanacar 		mvprintw(home_line, 0, "%s: ", curr_cmd->prompt);
118073baed14Scanacar 		attroff(A_STANDOUT);
118173baed14Scanacar 		printw("%s", cmdbuf);
118273baed14Scanacar 	} else if (curr_message) {
118373baed14Scanacar 		mvprintw(home_line, 0, "> %s", curr_message);
118473baed14Scanacar 	}
118573baed14Scanacar 	clrtoeol();
118673baed14Scanacar }
118773baed14Scanacar 
118873baed14Scanacar 
118973baed14Scanacar void
cmd_keyboard(int ch)119073baed14Scanacar cmd_keyboard(int ch)
119173baed14Scanacar {
119273baed14Scanacar 	if (curr_cmd == NULL)
119373baed14Scanacar 		return;
119473baed14Scanacar 
119573baed14Scanacar 	if (ch > 0 && isprint(ch)) {
119673baed14Scanacar 		if (cmd_len < sizeof(cmdbuf) - 1) {
119773baed14Scanacar 			cmdbuf[cmd_len++] = ch;
119873baed14Scanacar 			cmdbuf[cmd_len] = 0;
119973baed14Scanacar 		} else
120073baed14Scanacar 			beep();
120173baed14Scanacar 	}
120273baed14Scanacar 
120373baed14Scanacar 	switch (ch) {
120473baed14Scanacar 	case KEY_ENTER:
120573baed14Scanacar 	case 0x0a:
120673baed14Scanacar 	case 0x0d:
120773baed14Scanacar 	{
120873baed14Scanacar 		struct command * c = command_set(NULL, NULL);
12093185e9c1Scanacar 		c->exec(cmdbuf);
121073baed14Scanacar 		break;
121173baed14Scanacar 	}
121273baed14Scanacar 	case KEY_BACKSPACE:
121373baed14Scanacar 	case KEY_DC:
121473baed14Scanacar 	case CTRL_H:
121573baed14Scanacar 		if (cmd_len > 0) {
121673baed14Scanacar 			cmdbuf[--cmd_len] = 0;
121773baed14Scanacar 		} else
121873baed14Scanacar 			beep();
121973baed14Scanacar 		break;
122073baed14Scanacar 	case 0x1b:
122173baed14Scanacar 	case CTRL_G:
122273baed14Scanacar 		if (cmd_len > 0) {
122373baed14Scanacar 			cmdbuf[0] = '\0';
122473baed14Scanacar 			cmd_len = 0;
122573baed14Scanacar 		} else
122673baed14Scanacar 			command_set(NULL, NULL);
122773baed14Scanacar 		break;
122873baed14Scanacar 	default:
122973baed14Scanacar 		break;
123073baed14Scanacar 	}
123173baed14Scanacar }
123273baed14Scanacar 
123373baed14Scanacar void
keyboard(void)123473baed14Scanacar keyboard(void)
123573baed14Scanacar {
123673baed14Scanacar 	int ch;
123773baed14Scanacar 
123873baed14Scanacar 	ch = getch();
123973baed14Scanacar 
124073baed14Scanacar 	if (curr_cmd) {
124173baed14Scanacar 		cmd_keyboard(ch);
124273baed14Scanacar 		print_cmdline();
124373baed14Scanacar 		return;
124473baed14Scanacar 	}
124573baed14Scanacar 
124673baed14Scanacar 	if (curr_mgr != NULL)
124773baed14Scanacar 		if (curr_mgr->key_fn != NULL)
124873baed14Scanacar 			if (curr_mgr->key_fn(ch))
124973baed14Scanacar 				return;
125073baed14Scanacar 
125173baed14Scanacar 	if (curr_message != NULL) {
125273baed14Scanacar 		if (ch > 0) {
1253e9b50d6aStb 			message_set(NULL);
125473baed14Scanacar 			need_update = 1;
125573baed14Scanacar 		}
125673baed14Scanacar 	}
125773baed14Scanacar 
125873baed14Scanacar 	switch (ch) {
125973baed14Scanacar 	case ' ':
126073baed14Scanacar 		gotsig_alarm = 1;
126173baed14Scanacar 		break;
126273baed14Scanacar 	case 'o':
126373baed14Scanacar 		next_order();
126473baed14Scanacar 		need_sort = 1;
126573baed14Scanacar 		break;
126673baed14Scanacar 	case 'p':
126773baed14Scanacar 		paused = !paused;
126873baed14Scanacar 		gotsig_alarm = 1;
126973baed14Scanacar 		break;
127073baed14Scanacar 	case 'q':
127173baed14Scanacar 		gotsig_close = 1;
127273baed14Scanacar 		break;
127373baed14Scanacar 	case 'r':
127473baed14Scanacar 		sortdir *= -1;
127573baed14Scanacar 		need_sort = 1;
127673baed14Scanacar 		break;
127773baed14Scanacar 	case 'v':
127873baed14Scanacar 		/* FALLTHROUGH */
127973baed14Scanacar 	case KEY_RIGHT:
128073baed14Scanacar 		/* FALLTHROUGH */
128173baed14Scanacar 	case CTRL_F:
128273baed14Scanacar 		next_view();
128373baed14Scanacar 		break;
128473baed14Scanacar 	case KEY_LEFT:
128573baed14Scanacar 		/* FALLTHROUGH */
128673baed14Scanacar 	case CTRL_B:
128773baed14Scanacar 		prev_view();
128873baed14Scanacar 		break;
128973baed14Scanacar 	case KEY_DOWN:
129073baed14Scanacar 		/* FALLTHROUGH */
129173baed14Scanacar 	case CTRL_N:
129273baed14Scanacar 		dispstart++;
129373baed14Scanacar 		need_update = 1;
129473baed14Scanacar 		break;
129573baed14Scanacar 	case KEY_UP:
129673baed14Scanacar 		/* FALLTHROUGH */
129773baed14Scanacar 	case CTRL_P:
129873baed14Scanacar 		dispstart--;
129973baed14Scanacar 		need_update = 1;
130073baed14Scanacar 		break;
130173baed14Scanacar 	case KEY_NPAGE:
130273baed14Scanacar 		/* FALLTHROUGH */
130373baed14Scanacar 	case CTRL_V:
130473baed14Scanacar 		dispstart += maxprint;
130573baed14Scanacar 		need_update = 1;
130673baed14Scanacar 		break;
130773baed14Scanacar 	case KEY_PPAGE:
130873baed14Scanacar 		/* FALLTHROUGH */
130973baed14Scanacar 	case META_V:
131073baed14Scanacar 		dispstart -= maxprint;
131173baed14Scanacar 		need_update = 1;
131273baed14Scanacar 		break;
131373baed14Scanacar 	case KEY_HOME:
131473baed14Scanacar 		/* FALLTHROUGH */
131573baed14Scanacar 	case CTRL_A:
131673baed14Scanacar 		dispstart = 0;
131773baed14Scanacar 		need_update = 1;
131873baed14Scanacar 		break;
131973baed14Scanacar 	case KEY_END:
132073baed14Scanacar 		/* FALLTHROUGH */
132173baed14Scanacar 	case CTRL_E:
132273baed14Scanacar 		dispstart = num_disp;
132373baed14Scanacar 		need_update = 1;
132473baed14Scanacar 		break;
132573baed14Scanacar 	case CTRL_L:
132673baed14Scanacar 		clear();
132773baed14Scanacar 		need_update = 1;
132873baed14Scanacar 		break;
132973baed14Scanacar 	default:
133073baed14Scanacar 		break;
133173baed14Scanacar 	}
133273baed14Scanacar 
133373baed14Scanacar 	if (set_order_hotkey(ch))
133473baed14Scanacar 		need_sort = 1;
133573baed14Scanacar 	else
133673baed14Scanacar 		set_view_hotkey(ch);
133773baed14Scanacar }
133873baed14Scanacar 
133973baed14Scanacar void
engine_initialize(void)134073baed14Scanacar engine_initialize(void)
134173baed14Scanacar {
134273baed14Scanacar 	signal(SIGTERM, sig_close);
134373baed14Scanacar 	signal(SIGINT, sig_close);
134473baed14Scanacar 	signal(SIGQUIT, sig_close);
134573baed14Scanacar 	signal(SIGWINCH, sig_resize);
134673baed14Scanacar 	signal(SIGALRM, sig_alarm);
134773baed14Scanacar }
134873baed14Scanacar 
134973baed14Scanacar void
engine_loop(int countmax)135073baed14Scanacar engine_loop(int countmax)
135173baed14Scanacar {
135273baed14Scanacar 	int count = 0;
135373baed14Scanacar 
135473baed14Scanacar 	for (;;) {
135573baed14Scanacar 		if (gotsig_alarm) {
135673baed14Scanacar 			read_view();
135773baed14Scanacar 			need_sort = 1;
135873baed14Scanacar 			gotsig_alarm = 0;
135907a32fc5Smillert 			setitimer(ITIMER_REAL, &it_delay, NULL);
136073baed14Scanacar 		}
136173baed14Scanacar 
136273baed14Scanacar 		if (need_sort) {
136373baed14Scanacar 			sort_view();
136473baed14Scanacar 			need_sort = 0;
136573baed14Scanacar 			need_update = 1;
136673baed14Scanacar 
136773baed14Scanacar 			/* XXX if sort took too long */
136873baed14Scanacar 			if (gotsig_alarm) {
136973baed14Scanacar 				gotsig_alarm = 0;
137007a32fc5Smillert 				setitimer(ITIMER_REAL, &it_delay, NULL);
137173baed14Scanacar 			}
137273baed14Scanacar 		}
137373baed14Scanacar 
137473baed14Scanacar 		if (need_update) {
137573baed14Scanacar 			erase();
1376c7d45d65Sreyk 			if (!averageonly ||
1377c7d45d65Sreyk 			    (averageonly && count == countmax - 1))
137873baed14Scanacar 				disp_update();
1379d539d1daSmartijn 			if (message_cont) {
1380d539d1daSmartijn 				switch (message_mode) {
1381d539d1daSmartijn 				case MESSAGE_NONE:
1382d539d1daSmartijn 					message_set(NULL);
1383d539d1daSmartijn 					break;
1384d539d1daSmartijn 				case MESSAGE_HELP:
1385d539d1daSmartijn 					show_help();
1386d539d1daSmartijn 					break;
1387d539d1daSmartijn 				case MESSAGE_VIEW:
1388d539d1daSmartijn 					show_view();
1389d539d1daSmartijn 					break;
1390d539d1daSmartijn 				case MESSAGE_ORDER:
1391d539d1daSmartijn 					show_order();
1392d539d1daSmartijn 					break;
1393d539d1daSmartijn 				}
1394d539d1daSmartijn 			}
139573baed14Scanacar 			end_page();
139673baed14Scanacar 			need_update = 0;
139773baed14Scanacar 			if (countmax && ++count >= countmax)
139873baed14Scanacar 				break;
139973baed14Scanacar 		}
140073baed14Scanacar 
140173baed14Scanacar 		if (gotsig_close)
140273baed14Scanacar 			break;
140373baed14Scanacar 		if (gotsig_resize) {
140481d8c4e1Snicm 			do_resize_term();
140573baed14Scanacar 			gotsig_resize = 0;
140673baed14Scanacar 			need_update = 1;
140773baed14Scanacar 		}
140873baed14Scanacar 
140973baed14Scanacar 		if (interactive && need_update == 0)
141073baed14Scanacar 			keyboard();
141173baed14Scanacar 		else if (interactive == 0)
141207a32fc5Smillert 			nanosleep(&ts_delay, NULL);
141373baed14Scanacar 	}
141473baed14Scanacar 
141573baed14Scanacar 	if (rawmode == 0)
141673baed14Scanacar 		endwin();
141773baed14Scanacar }
1418fcad183eSlum 
1419fcad183eSlum int
check_termcap(void)1420fcad183eSlum check_termcap(void)
1421fcad183eSlum {
1422fcad183eSlum 	char *term_name;
1423fcad183eSlum 	int status;
1424fcad183eSlum 	static struct termios screen_settings;
1425fcad183eSlum 
1426fcad183eSlum 	if (!interactive)
1427fcad183eSlum 		/* pretend we have a dumb terminal */
1428fcad183eSlum 		return(1);
1429fcad183eSlum 
1430fcad183eSlum 	/* get the terminal name */
1431fcad183eSlum 	term_name = getenv("TERM");
1432fcad183eSlum 	if (term_name == NULL)
1433fcad183eSlum 		return(1);
1434fcad183eSlum 
1435fcad183eSlum 	/* now get the termcap entry */
1436fcad183eSlum 	if ((status = tgetent(NULL, term_name)) != 1) {
1437fcad183eSlum 		if (status == -1)
1438fcad183eSlum 			warnx("can't open termcap file");
1439fcad183eSlum 		else
1440fcad183eSlum 			warnx("no termcap entry for a `%s' terminal",
1441fcad183eSlum 			    term_name);
1442fcad183eSlum 
1443fcad183eSlum 		/* pretend it's dumb and proceed */
1444fcad183eSlum 		return(1);
1445fcad183eSlum 	}
1446fcad183eSlum 
1447fcad183eSlum 	/* "hardcopy" immediately indicates a very stupid terminal */
1448fcad183eSlum 	if (tgetflag("hc"))
1449fcad183eSlum 		return(1);
1450fcad183eSlum 
1451fcad183eSlum         /* get necessary capabilities */
1452fcad183eSlum         if (tgetstr("cl", NULL) == NULL || tgetstr("cm", NULL) == NULL)
1453fcad183eSlum 		return(1);
1454fcad183eSlum 
1455fcad183eSlum 	/* if stdout is not a terminal, pretend we are a dumb terminal */
1456fcad183eSlum 	if (tcgetattr(STDOUT_FILENO, &screen_settings) == -1)
1457fcad183eSlum 		return(1);
1458fcad183eSlum 
1459fcad183eSlum 	return(0);
1460fcad183eSlum }
146107a32fc5Smillert 
146207a32fc5Smillert void
refresh_delay(double delay)146307a32fc5Smillert refresh_delay(double delay)
146407a32fc5Smillert {
146507a32fc5Smillert 	double secs, frac;
146607a32fc5Smillert 
146707a32fc5Smillert 	frac = modf(delay, &secs);
146807a32fc5Smillert 	ts_delay.tv_sec = secs;
146907a32fc5Smillert 	ts_delay.tv_nsec = frac * 1000000000.0;
147007a32fc5Smillert 	if (!timespecisset(&ts_delay))
147107a32fc5Smillert 		ts_delay.tv_nsec = 1000000000;
147207a32fc5Smillert 	TIMESPEC_TO_TIMEVAL(&it_delay.it_value, &ts_delay);
147307a32fc5Smillert }
1474