124139Sjoerg/*
224139Sjoerg *  Top users/processes display for Unix
324139Sjoerg *  Version 3
424139Sjoerg *
524139Sjoerg *  This program may be freely redistributed,
624139Sjoerg *  but this entire comment MUST remain intact.
724139Sjoerg *
824139Sjoerg *  Copyright (c) 1984, 1989, William LeFebvre, Rice University
924139Sjoerg *  Copyright (c) 1989, 1990, 1992, William LeFebvre, Northwestern University
1066641Simp *
1166641Simp * $FreeBSD: stable/11/contrib/top/display.c 332948 2018-04-24 17:37:29Z lidl $
1224139Sjoerg */
1324139Sjoerg
1424139Sjoerg/*
1524139Sjoerg *  This file contains the routines that display information on the screen.
1624139Sjoerg *  Each section of the screen has two routines:  one for initially writing
1724139Sjoerg *  all constant and dynamic text, and one for only updating the text that
1824139Sjoerg *  changes.  The prefix "i_" is used on all the "initial" routines and the
1924139Sjoerg *  prefix "u_" is used for all the "updating" routines.
2024139Sjoerg *
2124139Sjoerg *  ASSUMPTIONS:
2224139Sjoerg *        None of the "i_" routines use any of the termcap capabilities.
2324139Sjoerg *        In this way, those routines can be safely used on terminals that
2424139Sjoerg *        have minimal (or nonexistant) terminal capabilities.
2524139Sjoerg *
2624139Sjoerg *        The routines are called in this order:  *_loadave, i_timeofday,
2724139Sjoerg *        *_procstates, *_cpustates, *_memory, *_message, *_header,
2824139Sjoerg *        *_process, u_endscreen.
2924139Sjoerg */
3024139Sjoerg
3124139Sjoerg#include "os.h"
32300395Sngie
33300395Sngie#include <sys/time.h>
34300395Sngie
35332948Slidl#include <curses.h>
3624139Sjoerg#include <ctype.h>
37332948Slidl#include <termcap.h>
3824139Sjoerg#include <time.h>
39300395Sngie#include <unistd.h>
4024139Sjoerg
4124139Sjoerg#include "screen.h"		/* interface to screen package */
4224139Sjoerg#include "layout.h"		/* defines for screen position layout */
4324139Sjoerg#include "display.h"
4424139Sjoerg#include "top.h"
4524139Sjoerg#include "top.local.h"
4624139Sjoerg#include "boolean.h"
4724139Sjoerg#include "machine.h"		/* we should eliminate this!!! */
4824139Sjoerg#include "utils.h"
4924139Sjoerg
5024139Sjoerg#ifdef DEBUG
5124139SjoergFILE *debug;
5224139Sjoerg#endif
5324139Sjoerg
5424139Sjoerg/* imported from screen.c */
5524139Sjoergextern int overstrike;
5624139Sjoerg
5724139Sjoergstatic int lmpid = 0;
5824139Sjoergstatic int last_hi = 0;		/* used in u_process and u_endscreen */
5924139Sjoergstatic int lastline = 0;
6024139Sjoergstatic int display_width = MAX_COLS;
6124139Sjoerg
6224139Sjoerg#define lineindex(l) ((l)*display_width)
6324139Sjoerg
6424139Sjoerg
6524139Sjoerg/* things initialized by display_init and used thruout */
6624139Sjoerg
6724139Sjoerg/* buffer of proc information lines for display updating */
6824139Sjoergchar *screenbuf = NULL;
6924139Sjoerg
7024139Sjoergstatic char **procstate_names;
7124139Sjoergstatic char **cpustate_names;
7224139Sjoergstatic char **memory_names;
73237656Sjhbstatic char **arc_names;
74318449Sallanjudestatic char **carc_names;
7524142Sjoergstatic char **swap_names;
7624139Sjoerg
7724139Sjoergstatic int num_procstates;
7824139Sjoergstatic int num_cpustates;
7924139Sjoergstatic int num_memory;
8024142Sjoergstatic int num_swap;
8124139Sjoerg
8224139Sjoergstatic int *lprocstates;
8324139Sjoergstatic int *lcpustates;
8424139Sjoergstatic int *lmemory;
8524142Sjoergstatic int *lswap;
8624139Sjoerg
87175420Speterstatic int num_cpus;
8824139Sjoergstatic int *cpustate_columns;
8924139Sjoergstatic int cpustate_total_length;
90175420Speterstatic int cpustates_column;
9124139Sjoerg
9224139Sjoergstatic enum { OFF, ON, ERASE } header_status = ON;
9324139Sjoerg
9424139Sjoergstatic int string_count();
9524139Sjoergstatic void summary_format();
9624139Sjoergstatic void line_update();
9724139Sjoerg
98175420Speterint  x_lastpid =	10;
99175420Speterint  y_lastpid =	0;
100175420Speterint  x_loadave =	33;
101175420Speterint  x_loadave_nompid =	15;
102175420Speterint  y_loadave =	0;
103175420Speterint  x_procstate =	0;
104175420Speterint  y_procstate =	1;
105175420Speterint  x_brkdn =		15;
106175420Speterint  y_brkdn =		1;
107175420Speterint  x_mem =		5;
108175420Speterint  y_mem =		3;
109237656Sjhbint  x_arc =		5;
110237656Sjhbint  y_arc =		4;
111318449Sallanjudeint  x_carc =		5;
112318449Sallanjudeint  y_carc =		5;
113175420Speterint  x_swap =		6;
114175420Speterint  y_swap =		4;
115175420Speterint  y_message =	5;
116175420Speterint  x_header =		0;
117175420Speterint  y_header =		6;
118175420Speterint  x_idlecursor =	0;
119175420Speterint  y_idlecursor =	5;
120175420Speterint  y_procs =		7;
121175420Speter
122175420Speterint  y_cpustates =	2;
123175420Speterint  Header_lines =	7;
124175420Speter
12524139Sjoergint display_resize()
12624139Sjoerg
12724139Sjoerg{
12824139Sjoerg    register int lines;
12924139Sjoerg
13024139Sjoerg    /* first, deallocate any previous buffer that may have been there */
13124139Sjoerg    if (screenbuf != NULL)
13224139Sjoerg    {
13324139Sjoerg	free(screenbuf);
13424139Sjoerg    }
13524139Sjoerg
13624139Sjoerg    /* calculate the current dimensions */
13724139Sjoerg    /* if operating in "dumb" mode, we only need one line */
13824139Sjoerg    lines = smart_terminal ? screen_length - Header_lines : 1;
13924139Sjoerg
140101692Sdwmalone    if (lines < 0)
141101692Sdwmalone	lines = 0;
14224139Sjoerg    /* we don't want more than MAX_COLS columns, since the machine-dependent
14324139Sjoerg       modules make static allocations based on MAX_COLS and we don't want
14424139Sjoerg       to run off the end of their buffers */
14524139Sjoerg    display_width = screen_width;
14624139Sjoerg    if (display_width >= MAX_COLS)
14724139Sjoerg    {
14824139Sjoerg	display_width = MAX_COLS - 1;
14924139Sjoerg    }
15024139Sjoerg
15124139Sjoerg    /* now, allocate space for the screen buffer */
15224139Sjoerg    screenbuf = (char *)malloc(lines * display_width);
15324139Sjoerg    if (screenbuf == (char *)NULL)
15424139Sjoerg    {
15524139Sjoerg	/* oops! */
15624139Sjoerg	return(-1);
15724139Sjoerg    }
15824139Sjoerg
15924139Sjoerg    /* return number of lines available */
16024139Sjoerg    /* for dumb terminals, pretend like we can show any amount */
16124139Sjoerg    return(smart_terminal ? lines : Largest);
16224139Sjoerg}
16324139Sjoerg
164223936Sjhbint display_updatecpus(statics)
16524139Sjoerg
16624139Sjoergstruct statics *statics;
16724139Sjoerg
16824139Sjoerg{
169224205Sjhb    register int *lp;
17024139Sjoerg    register int lines;
17124139Sjoerg    register int i;
172223936Sjhb
17324139Sjoerg    /* call resize to do the dirty work */
17424139Sjoerg    lines = display_resize();
175224205Sjhb    if (pcpu_stats)
176224205Sjhb	num_cpus = statics->ncpus;
177224205Sjhb    else
178224205Sjhb	num_cpus = 1;
179175420Speter    cpustates_column = 5;	/* CPU: */
180175420Speter    if (num_cpus != 1)
181175420Speter    cpustates_column += 2;	/* CPU 0: */
182175420Speter    for (i = num_cpus; i > 9; i /= 10)
183175420Speter	cpustates_column++;
18424139Sjoerg
185224205Sjhb    /* fill the "last" array with all -1s, to insure correct updating */
186224205Sjhb    lp = lcpustates;
187224205Sjhb    i = num_cpustates * num_cpus;
188224205Sjhb    while (--i >= 0)
189224205Sjhb    {
190224205Sjhb	*lp++ = -1;
191224205Sjhb    }
192224205Sjhb
193223936Sjhb    return(lines);
194223936Sjhb}
195223936Sjhb
196223936Sjhbint display_init(statics)
197223936Sjhb
198223936Sjhbstruct statics *statics;
199223936Sjhb
200223936Sjhb{
201223936Sjhb    register int lines;
202223936Sjhb    register char **pp;
203223936Sjhb    register int *ip;
204223936Sjhb    register int i;
205223936Sjhb
206223936Sjhb    lines = display_updatecpus(statics);
207223936Sjhb
20824139Sjoerg    /* only do the rest if we need to */
20924139Sjoerg    if (lines > -1)
21024139Sjoerg    {
21124139Sjoerg	/* save pointers and allocate space for names */
21224139Sjoerg	procstate_names = statics->procstate_names;
21324139Sjoerg	num_procstates = string_count(procstate_names);
21424139Sjoerg	lprocstates = (int *)malloc(num_procstates * sizeof(int));
21524139Sjoerg
21624139Sjoerg	cpustate_names = statics->cpustate_names;
21724142Sjoerg
21824142Sjoerg	swap_names = statics->swap_names;
21924142Sjoerg	num_swap = string_count(swap_names);
22024142Sjoerg	lswap = (int *)malloc(num_swap * sizeof(int));
22124139Sjoerg	num_cpustates = string_count(cpustate_names);
222224205Sjhb	lcpustates = (int *)malloc(num_cpustates * sizeof(int) * statics->ncpus);
22324139Sjoerg	cpustate_columns = (int *)malloc(num_cpustates * sizeof(int));
22424139Sjoerg
22524139Sjoerg	memory_names = statics->memory_names;
22624139Sjoerg	num_memory = string_count(memory_names);
22724139Sjoerg	lmemory = (int *)malloc(num_memory * sizeof(int));
22824139Sjoerg
229237656Sjhb	arc_names = statics->arc_names;
230318449Sallanjude	carc_names = statics->carc_names;
231237656Sjhb
23224139Sjoerg	/* calculate starting columns where needed */
23324139Sjoerg	cpustate_total_length = 0;
23424139Sjoerg	pp = cpustate_names;
23524139Sjoerg	ip = cpustate_columns;
23624139Sjoerg	while (*pp != NULL)
23724139Sjoerg	{
23889758Sdwmalone	    *ip++ = cpustate_total_length;
23924139Sjoerg	    if ((i = strlen(*pp++)) > 0)
24024139Sjoerg	    {
24124139Sjoerg		cpustate_total_length += i + 8;
24224139Sjoerg	    }
24324139Sjoerg	}
24424139Sjoerg    }
24524139Sjoerg
24624139Sjoerg    /* return number of lines available */
24724139Sjoerg    return(lines);
24824139Sjoerg}
24924139Sjoerg
250300395Sngievoid
25124139Sjoergi_loadave(mpid, avenrun)
25224139Sjoerg
25324139Sjoergint mpid;
25424139Sjoergdouble *avenrun;
25524139Sjoerg
25624139Sjoerg{
25724139Sjoerg    register int i;
25824139Sjoerg
25924139Sjoerg    /* i_loadave also clears the screen, since it is first */
260332948Slidl    top_clear();
26124139Sjoerg
26224139Sjoerg    /* mpid == -1 implies this system doesn't have an _mpid */
26324139Sjoerg    if (mpid != -1)
26424139Sjoerg    {
26524139Sjoerg	printf("last pid: %5d;  ", mpid);
26624139Sjoerg    }
26724139Sjoerg
26824139Sjoerg    printf("load averages");
26924139Sjoerg
27024139Sjoerg    for (i = 0; i < 3; i++)
27124139Sjoerg    {
27224139Sjoerg	printf("%c %5.2f",
27324139Sjoerg	    i == 0 ? ':' : ',',
27424139Sjoerg	    avenrun[i]);
27524139Sjoerg    }
27624139Sjoerg    lmpid = mpid;
27724139Sjoerg}
27824139Sjoerg
279300395Sngievoid
28024139Sjoergu_loadave(mpid, avenrun)
28124139Sjoerg
28224139Sjoergint mpid;
28324139Sjoergdouble *avenrun;
28424139Sjoerg
28524139Sjoerg{
28624139Sjoerg    register int i;
28724139Sjoerg
28824139Sjoerg    if (mpid != -1)
28924139Sjoerg    {
29024139Sjoerg	/* change screen only when value has really changed */
29124139Sjoerg	if (mpid != lmpid)
29224139Sjoerg	{
29324139Sjoerg	    Move_to(x_lastpid, y_lastpid);
29424139Sjoerg	    printf("%5d", mpid);
29524139Sjoerg	    lmpid = mpid;
29624139Sjoerg	}
29724139Sjoerg
29824139Sjoerg	/* i remembers x coordinate to move to */
29924139Sjoerg	i = x_loadave;
30024139Sjoerg    }
30124139Sjoerg    else
30224139Sjoerg    {
30324139Sjoerg	i = x_loadave_nompid;
30424139Sjoerg    }
30524139Sjoerg
30624139Sjoerg    /* move into position for load averages */
30724139Sjoerg    Move_to(i, y_loadave);
30824139Sjoerg
30924139Sjoerg    /* display new load averages */
31024139Sjoerg    /* we should optimize this and only display changes */
31124139Sjoerg    for (i = 0; i < 3; i++)
31224139Sjoerg    {
31324139Sjoerg	printf("%s%5.2f",
31424139Sjoerg	    i == 0 ? "" : ", ",
31524139Sjoerg	    avenrun[i]);
31624139Sjoerg    }
31724139Sjoerg}
31824139Sjoerg
319300395Sngievoid
32024139Sjoergi_timeofday(tod)
32124139Sjoerg
32224139Sjoergtime_t *tod;
32324139Sjoerg
32424139Sjoerg{
32524139Sjoerg    /*
32624139Sjoerg     *  Display the current time.
32724139Sjoerg     *  "ctime" always returns a string that looks like this:
32824139Sjoerg     *
32924139Sjoerg     *	Sun Sep 16 01:03:52 1973
33024139Sjoerg     *      012345678901234567890123
33124139Sjoerg     *	          1         2
33224139Sjoerg     *
33324139Sjoerg     *  We want indices 11 thru 18 (length 8).
33424139Sjoerg     */
33524139Sjoerg
33624139Sjoerg    if (smart_terminal)
33724139Sjoerg    {
33824139Sjoerg	Move_to(screen_width - 8, 0);
33924139Sjoerg    }
34024139Sjoerg    else
34124139Sjoerg    {
34224139Sjoerg	fputs("    ", stdout);
34324139Sjoerg    }
34424139Sjoerg#ifdef DEBUG
34524139Sjoerg    {
34624139Sjoerg	char *foo;
34724139Sjoerg	foo = ctime(tod);
34824139Sjoerg	fputs(foo, stdout);
34924139Sjoerg    }
35024139Sjoerg#endif
35124139Sjoerg    printf("%-8.8s\n", &(ctime(tod)[11]));
35224139Sjoerg    lastline = 1;
35324139Sjoerg}
35424139Sjoerg
35524139Sjoergstatic int ltotal = 0;
35689758Sdwmalonestatic char procstates_buffer[MAX_COLS];
35724139Sjoerg
35824139Sjoerg/*
35924139Sjoerg *  *_procstates(total, brkdn, names) - print the process summary line
36024139Sjoerg *
36124139Sjoerg *  Assumptions:  cursor is at the beginning of the line on entry
36224139Sjoerg *		  lastline is valid
36324139Sjoerg */
36424139Sjoerg
365300395Sngievoid
36624139Sjoergi_procstates(total, brkdn)
36724139Sjoerg
36824139Sjoergint total;
36924139Sjoergint *brkdn;
37024139Sjoerg
37124139Sjoerg{
37224139Sjoerg    register int i;
37324139Sjoerg
37424139Sjoerg    /* write current number of processes and remember the value */
37524139Sjoerg    printf("%d processes:", total);
37624139Sjoerg    ltotal = total;
37724139Sjoerg
37824139Sjoerg    /* put out enough spaces to get to column 15 */
37924139Sjoerg    i = digits(total);
38024139Sjoerg    while (i++ < 4)
38124139Sjoerg    {
38224139Sjoerg	putchar(' ');
38324139Sjoerg    }
38424139Sjoerg
38524139Sjoerg    /* format and print the process state summary */
38624139Sjoerg    summary_format(procstates_buffer, brkdn, procstate_names);
38724139Sjoerg    fputs(procstates_buffer, stdout);
38824139Sjoerg
38924139Sjoerg    /* save the numbers for next time */
39024139Sjoerg    memcpy(lprocstates, brkdn, num_procstates * sizeof(int));
39124139Sjoerg}
39224139Sjoerg
393300395Sngievoid
39424139Sjoergu_procstates(total, brkdn)
39524139Sjoerg
39624139Sjoergint total;
39724139Sjoergint *brkdn;
39824139Sjoerg
39924139Sjoerg{
40089758Sdwmalone    static char new[MAX_COLS];
40124139Sjoerg    register int i;
40224139Sjoerg
40324139Sjoerg    /* update number of processes only if it has changed */
40424139Sjoerg    if (ltotal != total)
40524139Sjoerg    {
40624139Sjoerg	/* move and overwrite */
40724139Sjoerg#if (x_procstate == 0)
40824139Sjoerg	Move_to(x_procstate, y_procstate);
40924139Sjoerg#else
41024139Sjoerg	/* cursor is already there...no motion needed */
41124139Sjoerg	/* assert(lastline == 1); */
41224139Sjoerg#endif
41324139Sjoerg	printf("%d", total);
41424139Sjoerg
41524139Sjoerg	/* if number of digits differs, rewrite the label */
41624139Sjoerg	if (digits(total) != digits(ltotal))
41724139Sjoerg	{
41824139Sjoerg	    fputs(" processes:", stdout);
41924139Sjoerg	    /* put out enough spaces to get to column 15 */
42024139Sjoerg	    i = digits(total);
42124139Sjoerg	    while (i++ < 4)
42224139Sjoerg	    {
42324139Sjoerg		putchar(' ');
42424139Sjoerg	    }
42524139Sjoerg	    /* cursor may end up right where we want it!!! */
42624139Sjoerg	}
42724139Sjoerg
42824139Sjoerg	/* save new total */
42924139Sjoerg	ltotal = total;
43024139Sjoerg    }
43124139Sjoerg
43224139Sjoerg    /* see if any of the state numbers has changed */
43324139Sjoerg    if (memcmp(lprocstates, brkdn, num_procstates * sizeof(int)) != 0)
43424139Sjoerg    {
43524139Sjoerg	/* format and update the line */
43624139Sjoerg	summary_format(new, brkdn, procstate_names);
43724139Sjoerg	line_update(procstates_buffer, new, x_brkdn, y_brkdn);
43824139Sjoerg	memcpy(lprocstates, brkdn, num_procstates * sizeof(int));
43924139Sjoerg    }
44024139Sjoerg}
44124139Sjoerg
442175420Speter#ifdef no_more
44324139Sjoerg/*
44424139Sjoerg *  *_cpustates(states, names) - print the cpu state percentages
44524139Sjoerg *
44624139Sjoerg *  Assumptions:  cursor is on the PREVIOUS line
44724139Sjoerg */
44824139Sjoerg
44924139Sjoerg/* cpustates_tag() calculates the correct tag to use to label the line */
45024139Sjoerg
45124139Sjoergchar *cpustates_tag()
45224139Sjoerg
45324139Sjoerg{
45424139Sjoerg    register char *use;
45524139Sjoerg
45624139Sjoerg    static char *short_tag = "CPU: ";
45724139Sjoerg    static char *long_tag = "CPU states: ";
45824139Sjoerg
45924139Sjoerg    /* if length + strlen(long_tag) >= screen_width, then we have to
46024139Sjoerg       use the shorter tag (we subtract 2 to account for ": ") */
46124139Sjoerg    if (cpustate_total_length + (int)strlen(long_tag) - 2 >= screen_width)
46224139Sjoerg    {
46324139Sjoerg	use = short_tag;
46424139Sjoerg    }
46524139Sjoerg    else
46624139Sjoerg    {
46724139Sjoerg	use = long_tag;
46824139Sjoerg    }
46924139Sjoerg
47024139Sjoerg    /* set cpustates_column accordingly then return result */
47124139Sjoerg    cpustates_column = strlen(use);
47224139Sjoerg    return(use);
47324139Sjoerg}
474175420Speter#endif
47524139Sjoerg
476300395Sngievoid
47724139Sjoergi_cpustates(states)
47824139Sjoerg
479300395Sngieint *states;
48024139Sjoerg
48124139Sjoerg{
48224139Sjoerg    register int i = 0;
48324139Sjoerg    register int value;
484175420Speter    register char **names;
48524139Sjoerg    register char *thisname;
486175420Speter    int cpu;
48724139Sjoerg
488175420Speterfor (cpu = 0; cpu < num_cpus; cpu++) {
489175420Speter    names = cpustate_names;
490175420Speter
49124139Sjoerg    /* print tag and bump lastline */
492175420Speter    if (num_cpus == 1)
493175420Speter	printf("\nCPU: ");
494218171Sjhb    else {
495218171Sjhb	value = printf("\nCPU %d: ", cpu);
496218171Sjhb	while (value++ <= cpustates_column)
497218171Sjhb		printf(" ");
498218171Sjhb    }
49924139Sjoerg    lastline++;
50024139Sjoerg
50124139Sjoerg    /* now walk thru the names and print the line */
50224139Sjoerg    while ((thisname = *names++) != NULL)
50324139Sjoerg    {
50424139Sjoerg	if (*thisname != '\0')
50524139Sjoerg	{
50624139Sjoerg	    /* retrieve the value and remember it */
50724139Sjoerg	    value = *states++;
50824139Sjoerg
50924139Sjoerg	    /* if percentage is >= 1000, print it as 100% */
51024139Sjoerg	    printf((value >= 1000 ? "%s%4.0f%% %s" : "%s%4.1f%% %s"),
511175420Speter		   (i++ % num_cpustates) == 0 ? "" : ", ",
51224139Sjoerg		   ((float)value)/10.,
51324139Sjoerg		   thisname);
51424139Sjoerg	}
51524139Sjoerg    }
516175420Speter}
51724139Sjoerg
51824139Sjoerg    /* copy over values into "last" array */
519175420Speter    memcpy(lcpustates, states, num_cpustates * sizeof(int) * num_cpus);
52024139Sjoerg}
52124139Sjoerg
522300395Sngievoid
52324139Sjoergu_cpustates(states)
52424139Sjoerg
525300395Sngieint *states;
52624139Sjoerg
52724139Sjoerg{
52824139Sjoerg    register int value;
529175420Speter    register char **names;
53024139Sjoerg    register char *thisname;
53124139Sjoerg    register int *lp;
53224139Sjoerg    register int *colp;
533175420Speter    int cpu;
53424139Sjoerg
535175420Speterfor (cpu = 0; cpu < num_cpus; cpu++) {
536175420Speter    names = cpustate_names;
537175420Speter
538175420Speter    Move_to(cpustates_column, y_cpustates + cpu);
539175420Speter    lastline = y_cpustates + cpu;
540175420Speter    lp = lcpustates + (cpu * num_cpustates);
54124139Sjoerg    colp = cpustate_columns;
54224139Sjoerg
54324139Sjoerg    /* we could be much more optimal about this */
54424139Sjoerg    while ((thisname = *names++) != NULL)
54524139Sjoerg    {
54624139Sjoerg	if (*thisname != '\0')
54724139Sjoerg	{
54824139Sjoerg	    /* did the value change since last time? */
54924139Sjoerg	    if (*lp != *states)
55024139Sjoerg	    {
55124139Sjoerg		/* yes, move and change */
552175420Speter		Move_to(cpustates_column + *colp, y_cpustates + cpu);
553175420Speter		lastline = y_cpustates + cpu;
55424139Sjoerg
55524139Sjoerg		/* retrieve value and remember it */
55624139Sjoerg		value = *states;
55724139Sjoerg
55824139Sjoerg		/* if percentage is >= 1000, print it as 100% */
55924139Sjoerg		printf((value >= 1000 ? "%4.0f" : "%4.1f"),
56024139Sjoerg		       ((double)value)/10.);
56124139Sjoerg
56224139Sjoerg		/* remember it for next time */
56389758Sdwmalone		*lp = value;
56424139Sjoerg	    }
56524139Sjoerg	}
56624139Sjoerg
56724139Sjoerg	/* increment and move on */
56824139Sjoerg	lp++;
56924139Sjoerg	states++;
57024139Sjoerg	colp++;
57124139Sjoerg    }
57224139Sjoerg}
573175420Speter}
57424139Sjoerg
575300395Sngievoid
57624139Sjoergz_cpustates()
57724139Sjoerg
57824139Sjoerg{
57924139Sjoerg    register int i = 0;
580175420Speter    register char **names;
58124139Sjoerg    register char *thisname;
58224139Sjoerg    register int *lp;
583218171Sjhb    int cpu, value;
58424139Sjoerg
585175420Speterfor (cpu = 0; cpu < num_cpus; cpu++) {
586175420Speter    names = cpustate_names;
587175420Speter
58824139Sjoerg    /* show tag and bump lastline */
589175420Speter    if (num_cpus == 1)
590175420Speter	printf("\nCPU: ");
591218171Sjhb    else {
592218171Sjhb	value = printf("\nCPU %d: ", cpu);
593218171Sjhb	while (value++ <= cpustates_column)
594218171Sjhb		printf(" ");
595218171Sjhb    }
59624139Sjoerg    lastline++;
59724139Sjoerg
59824139Sjoerg    while ((thisname = *names++) != NULL)
59924139Sjoerg    {
60024139Sjoerg	if (*thisname != '\0')
60124139Sjoerg	{
602175420Speter	    printf("%s    %% %s", (i++ % num_cpustates) == 0 ? "" : ", ", thisname);
60324139Sjoerg	}
60424139Sjoerg    }
605175420Speter}
60624139Sjoerg
60724139Sjoerg    /* fill the "last" array with all -1s, to insure correct updating */
60824139Sjoerg    lp = lcpustates;
609175420Speter    i = num_cpustates * num_cpus;
61024139Sjoerg    while (--i >= 0)
61124139Sjoerg    {
61224139Sjoerg	*lp++ = -1;
61324139Sjoerg    }
61424139Sjoerg}
61524139Sjoerg
61624139Sjoerg/*
61724139Sjoerg *  *_memory(stats) - print "Memory: " followed by the memory summary string
61824139Sjoerg *
61924139Sjoerg *  Assumptions:  cursor is on "lastline"
62024139Sjoerg *                for i_memory ONLY: cursor is on the previous line
62124139Sjoerg */
62224139Sjoerg
62324139Sjoergchar memory_buffer[MAX_COLS];
62424139Sjoerg
625300395Sngievoid
62624139Sjoergi_memory(stats)
62724139Sjoerg
62824139Sjoergint *stats;
62924139Sjoerg
63024139Sjoerg{
63124142Sjoerg    fputs("\nMem: ", stdout);
63224139Sjoerg    lastline++;
63324139Sjoerg
63424139Sjoerg    /* format and print the memory summary */
63524139Sjoerg    summary_format(memory_buffer, stats, memory_names);
63624139Sjoerg    fputs(memory_buffer, stdout);
63724139Sjoerg}
63824139Sjoerg
639300395Sngievoid
64024139Sjoergu_memory(stats)
64124139Sjoerg
64224139Sjoergint *stats;
64324139Sjoerg
64424139Sjoerg{
64524139Sjoerg    static char new[MAX_COLS];
64624139Sjoerg
64724139Sjoerg    /* format the new line */
64824139Sjoerg    summary_format(new, stats, memory_names);
64924139Sjoerg    line_update(memory_buffer, new, x_mem, y_mem);
65024139Sjoerg}
65124139Sjoerg
65224139Sjoerg/*
653237656Sjhb *  *_arc(stats) - print "ARC: " followed by the ARC summary string
654237656Sjhb *
655237656Sjhb *  Assumptions:  cursor is on "lastline"
656237656Sjhb *                for i_arc ONLY: cursor is on the previous line
657237656Sjhb */
658237656Sjhbchar arc_buffer[MAX_COLS];
659237656Sjhb
660300395Sngievoid
661237656Sjhbi_arc(stats)
662237656Sjhb
663237656Sjhbint *stats;
664237656Sjhb
665237656Sjhb{
666237656Sjhb    if (arc_names == NULL)
667300395Sngie	return;
668237656Sjhb
669237656Sjhb    fputs("\nARC: ", stdout);
670237656Sjhb    lastline++;
671237656Sjhb
672237656Sjhb    /* format and print the memory summary */
673237656Sjhb    summary_format(arc_buffer, stats, arc_names);
674237656Sjhb    fputs(arc_buffer, stdout);
675237656Sjhb}
676237656Sjhb
677300395Sngievoid
678237656Sjhbu_arc(stats)
679237656Sjhb
680237656Sjhbint *stats;
681237656Sjhb
682237656Sjhb{
683237656Sjhb    static char new[MAX_COLS];
684237656Sjhb
685237656Sjhb    if (arc_names == NULL)
686300395Sngie	return;
687237656Sjhb
688237656Sjhb    /* format the new line */
689237656Sjhb    summary_format(new, stats, arc_names);
690237656Sjhb    line_update(arc_buffer, new, x_arc, y_arc);
691237656Sjhb}
692237656Sjhb
693318449Sallanjude
694318449Sallanjude/*
695318449Sallanjude *  *_carc(stats) - print "Compressed ARC: " followed by the summary string
696318449Sallanjude *
697318449Sallanjude *  Assumptions:  cursor is on "lastline"
698318449Sallanjude *                for i_carc ONLY: cursor is on the previous line
699318449Sallanjude */
700318449Sallanjudechar carc_buffer[MAX_COLS];
701318449Sallanjude
702318449Sallanjudevoid
703318449Sallanjudei_carc(stats)
704318449Sallanjude
705318449Sallanjudeint *stats;
706318449Sallanjude
707318449Sallanjude{
708318449Sallanjude    if (carc_names == NULL)
709318449Sallanjude	return;
710318449Sallanjude
711318449Sallanjude    fputs("\n     ", stdout);
712318449Sallanjude    lastline++;
713318449Sallanjude
714318449Sallanjude    /* format and print the memory summary */
715318449Sallanjude    summary_format(carc_buffer, stats, carc_names);
716318449Sallanjude    fputs(carc_buffer, stdout);
717318449Sallanjude}
718318449Sallanjude
719318449Sallanjudevoid
720318449Sallanjudeu_carc(stats)
721318449Sallanjude
722318449Sallanjudeint *stats;
723318449Sallanjude
724318449Sallanjude{
725318449Sallanjude    static char new[MAX_COLS];
726318449Sallanjude
727318449Sallanjude    if (carc_names == NULL)
728318449Sallanjude	return;
729318449Sallanjude
730318449Sallanjude    /* format the new line */
731318449Sallanjude    summary_format(new, stats, carc_names);
732318449Sallanjude    line_update(carc_buffer, new, x_carc, y_carc);
733318449Sallanjude}
734237656Sjhb
735237656Sjhb/*
73624142Sjoerg *  *_swap(stats) - print "Swap: " followed by the swap summary string
73724142Sjoerg *
73824142Sjoerg *  Assumptions:  cursor is on "lastline"
73924142Sjoerg *                for i_swap ONLY: cursor is on the previous line
74024142Sjoerg */
74124142Sjoerg
74224142Sjoergchar swap_buffer[MAX_COLS];
74324142Sjoerg
744300395Sngievoid
74524142Sjoergi_swap(stats)
74624142Sjoerg
74724142Sjoergint *stats;
74824142Sjoerg
74924142Sjoerg{
75024142Sjoerg    fputs("\nSwap: ", stdout);
75124142Sjoerg    lastline++;
75224142Sjoerg
75324142Sjoerg    /* format and print the swap summary */
75424142Sjoerg    summary_format(swap_buffer, stats, swap_names);
75524142Sjoerg    fputs(swap_buffer, stdout);
75624142Sjoerg}
75724142Sjoerg
758300395Sngievoid
75924142Sjoergu_swap(stats)
76024142Sjoerg
76124142Sjoergint *stats;
76224142Sjoerg
76324142Sjoerg{
76424142Sjoerg    static char new[MAX_COLS];
76524142Sjoerg
76624142Sjoerg    /* format the new line */
76724142Sjoerg    summary_format(new, stats, swap_names);
76824142Sjoerg    line_update(swap_buffer, new, x_swap, y_swap);
76924142Sjoerg}
77024142Sjoerg
77124142Sjoerg/*
77224139Sjoerg *  *_message() - print the next pending message line, or erase the one
77324139Sjoerg *                that is there.
77424139Sjoerg *
77524139Sjoerg *  Note that u_message is (currently) the same as i_message.
77624139Sjoerg *
77724139Sjoerg *  Assumptions:  lastline is consistent
77824139Sjoerg */
77924139Sjoerg
78024139Sjoerg/*
78124139Sjoerg *  i_message is funny because it gets its message asynchronously (with
78224139Sjoerg *	respect to screen updates).
78324139Sjoerg */
78424139Sjoerg
78524139Sjoergstatic char next_msg[MAX_COLS + 5];
78624139Sjoergstatic int msglen = 0;
78724139Sjoerg/* Invariant: msglen is always the length of the message currently displayed
78824139Sjoerg   on the screen (even when next_msg doesn't contain that message). */
78924139Sjoerg
790300395Sngievoid
79124139Sjoergi_message()
79224139Sjoerg
79324139Sjoerg{
79424139Sjoerg    while (lastline < y_message)
79524139Sjoerg    {
79624139Sjoerg	fputc('\n', stdout);
79724139Sjoerg	lastline++;
79824139Sjoerg    }
79924139Sjoerg    if (next_msg[0] != '\0')
80024139Sjoerg    {
801332948Slidl	top_standout(next_msg);
80224139Sjoerg	msglen = strlen(next_msg);
80324139Sjoerg	next_msg[0] = '\0';
80424139Sjoerg    }
80524139Sjoerg    else if (msglen > 0)
80624139Sjoerg    {
80724139Sjoerg	(void) clear_eol(msglen);
80824139Sjoerg	msglen = 0;
80924139Sjoerg    }
81024139Sjoerg}
81124139Sjoerg
812300395Sngievoid
81324139Sjoergu_message()
81424139Sjoerg
81524139Sjoerg{
81624139Sjoerg    i_message();
81724139Sjoerg}
81824139Sjoerg
81924139Sjoergstatic int header_length;
82024139Sjoerg
82124139Sjoerg/*
822146344Skeramida * Trim a header string to the current display width and return a newly
823146344Skeramida * allocated area with the trimmed header.
824146344Skeramida */
825146344Skeramida
826146344Skeramidachar *
827146344Skeramidatrim_header(text)
828146344Skeramida
829146344Skeramidachar *text;
830146344Skeramida
831146344Skeramida{
832146344Skeramida	char *s;
833146344Skeramida	int width;
834146344Skeramida
835146344Skeramida	s = NULL;
836223342Sdelphij	width = display_width;
837146344Skeramida	header_length = strlen(text);
838146344Skeramida	if (header_length >= width) {
839146344Skeramida		s = malloc((width + 1) * sizeof(char));
840146344Skeramida		if (s == NULL)
841146344Skeramida			return (NULL);
842146344Skeramida		strncpy(s, text, width);
843146344Skeramida		s[width] = '\0';
844146344Skeramida	}
845146344Skeramida	return (s);
846146344Skeramida}
847146344Skeramida
848146344Skeramida/*
84924139Sjoerg *  *_header(text) - print the header for the process area
85024139Sjoerg *
85124139Sjoerg *  Assumptions:  cursor is on the previous line and lastline is consistent
85224139Sjoerg */
85324139Sjoerg
854300395Sngievoid
85524139Sjoergi_header(text)
85624139Sjoerg
85724139Sjoergchar *text;
85824139Sjoerg
85924139Sjoerg{
860146344Skeramida    char *s;
861146344Skeramida
862146344Skeramida    s = trim_header(text);
863146344Skeramida    if (s != NULL)
864146344Skeramida	text = s;
865146344Skeramida
86624139Sjoerg    if (header_status == ON)
86724139Sjoerg    {
86824139Sjoerg	putchar('\n');
869223342Sdelphij	fputs(text, stdout);
87024139Sjoerg	lastline++;
87124139Sjoerg    }
87224139Sjoerg    else if (header_status == ERASE)
87324139Sjoerg    {
87424139Sjoerg	header_status = OFF;
87524139Sjoerg    }
876146344Skeramida    free(s);
87724139Sjoerg}
87824139Sjoerg
87924139Sjoerg/*ARGSUSED*/
880300395Sngievoid
88124139Sjoergu_header(text)
88224139Sjoerg
883300395Sngiechar *text __unused;		/* ignored */
88424139Sjoerg
88524139Sjoerg{
886146344Skeramida
88724139Sjoerg    if (header_status == ERASE)
88824139Sjoerg    {
88924139Sjoerg	putchar('\n');
89024139Sjoerg	lastline++;
89124139Sjoerg	clear_eol(header_length);
89224139Sjoerg	header_status = OFF;
89324139Sjoerg    }
89424139Sjoerg}
89524139Sjoerg
89624139Sjoerg/*
89724139Sjoerg *  *_process(line, thisline) - print one process line
89824139Sjoerg *
89924139Sjoerg *  Assumptions:  lastline is consistent
90024139Sjoerg */
90124139Sjoerg
902300395Sngievoid
90324139Sjoergi_process(line, thisline)
90424139Sjoerg
90524139Sjoergint line;
90624139Sjoergchar *thisline;
90724139Sjoerg
90824139Sjoerg{
90924139Sjoerg    register char *p;
91024139Sjoerg    register char *base;
91124139Sjoerg
91224139Sjoerg    /* make sure we are on the correct line */
91324139Sjoerg    while (lastline < y_procs + line)
91424139Sjoerg    {
91524139Sjoerg	putchar('\n');
91624139Sjoerg	lastline++;
91724139Sjoerg    }
91824139Sjoerg
91924139Sjoerg    /* truncate the line to conform to our current screen width */
92024139Sjoerg    thisline[display_width] = '\0';
92124139Sjoerg
92224139Sjoerg    /* write the line out */
92324139Sjoerg    fputs(thisline, stdout);
92424139Sjoerg
92524139Sjoerg    /* copy it in to our buffer */
92624139Sjoerg    base = smart_terminal ? screenbuf + lineindex(line) : screenbuf;
92724139Sjoerg    p = strecpy(base, thisline);
92824139Sjoerg
92924139Sjoerg    /* zero fill the rest of it */
93024139Sjoerg    memzero(p, display_width - (p - base));
93124139Sjoerg}
93224139Sjoerg
933300395Sngievoid
93424139Sjoergu_process(line, newline)
93524139Sjoerg
93624139Sjoergint line;
93724139Sjoergchar *newline;
93824139Sjoerg
93924139Sjoerg{
94024139Sjoerg    register char *optr;
94124139Sjoerg    register int screen_line = line + Header_lines;
94224139Sjoerg    register char *bufferline;
94324139Sjoerg
94424139Sjoerg    /* remember a pointer to the current line in the screen buffer */
94524139Sjoerg    bufferline = &screenbuf[lineindex(line)];
94624139Sjoerg
94724139Sjoerg    /* truncate the line to conform to our current screen width */
94824139Sjoerg    newline[display_width] = '\0';
94924139Sjoerg
95024139Sjoerg    /* is line higher than we went on the last display? */
95124139Sjoerg    if (line >= last_hi)
95224139Sjoerg    {
95324139Sjoerg	/* yes, just ignore screenbuf and write it out directly */
95424139Sjoerg	/* get positioned on the correct line */
95524139Sjoerg	if (screen_line - lastline == 1)
95624139Sjoerg	{
95724139Sjoerg	    putchar('\n');
95824139Sjoerg	    lastline++;
95924139Sjoerg	}
96024139Sjoerg	else
96124139Sjoerg	{
96224139Sjoerg	    Move_to(0, screen_line);
96324139Sjoerg	    lastline = screen_line;
96424139Sjoerg	}
96524139Sjoerg
96624139Sjoerg	/* now write the line */
96724139Sjoerg	fputs(newline, stdout);
96824139Sjoerg
96924139Sjoerg	/* copy it in to the buffer */
97024139Sjoerg	optr = strecpy(bufferline, newline);
97124139Sjoerg
97224139Sjoerg	/* zero fill the rest of it */
97324139Sjoerg	memzero(optr, display_width - (optr - bufferline));
97424139Sjoerg    }
97524139Sjoerg    else
97624139Sjoerg    {
97724139Sjoerg	line_update(bufferline, newline, 0, line + Header_lines);
97824139Sjoerg    }
97924139Sjoerg}
98024139Sjoerg
981300395Sngievoid
98224139Sjoergu_endscreen(hi)
98324139Sjoerg
984300395Sngieint hi;
98524139Sjoerg
98624139Sjoerg{
98724139Sjoerg    register int screen_line = hi + Header_lines;
98824139Sjoerg    register int i;
98924139Sjoerg
99024139Sjoerg    if (smart_terminal)
99124139Sjoerg    {
99224139Sjoerg	if (hi < last_hi)
99324139Sjoerg	{
99424139Sjoerg	    /* need to blank the remainder of the screen */
99524139Sjoerg	    /* but only if there is any screen left below this line */
99624139Sjoerg	    if (lastline + 1 < screen_length)
99724139Sjoerg	    {
99824139Sjoerg		/* efficiently move to the end of currently displayed info */
99924139Sjoerg		if (screen_line - lastline < 5)
100024139Sjoerg		{
100124139Sjoerg		    while (lastline < screen_line)
100224139Sjoerg		    {
100324139Sjoerg			putchar('\n');
100424139Sjoerg			lastline++;
100524139Sjoerg		    }
100624139Sjoerg		}
100724139Sjoerg		else
100824139Sjoerg		{
100924139Sjoerg		    Move_to(0, screen_line);
101024139Sjoerg		    lastline = screen_line;
101124139Sjoerg		}
101224139Sjoerg
101324139Sjoerg		if (clear_to_end)
101424139Sjoerg		{
101524139Sjoerg		    /* we can do this the easy way */
101624139Sjoerg		    putcap(clear_to_end);
101724139Sjoerg		}
101824139Sjoerg		else
101924139Sjoerg		{
102024139Sjoerg		    /* use clear_eol on each line */
102124139Sjoerg		    i = hi;
102224139Sjoerg		    while ((void) clear_eol(strlen(&screenbuf[lineindex(i++)])), i < last_hi)
102324139Sjoerg		    {
102424139Sjoerg			putchar('\n');
102524139Sjoerg		    }
102624139Sjoerg		}
102724139Sjoerg	    }
102824139Sjoerg	}
102924139Sjoerg	last_hi = hi;
103024139Sjoerg
103124139Sjoerg	/* move the cursor to a pleasant place */
103224139Sjoerg	Move_to(x_idlecursor, y_idlecursor);
103324139Sjoerg	lastline = y_idlecursor;
103424139Sjoerg    }
103524139Sjoerg    else
103624139Sjoerg    {
103724139Sjoerg	/* separate this display from the next with some vertical room */
103824139Sjoerg	fputs("\n\n", stdout);
103924139Sjoerg    }
104024139Sjoerg}
104124139Sjoerg
1042300395Sngievoid
104324139Sjoergdisplay_header(t)
104424139Sjoerg
104524139Sjoergint t;
104624139Sjoerg
104724139Sjoerg{
104824139Sjoerg    if (t)
104924139Sjoerg    {
105024139Sjoerg	header_status = ON;
105124139Sjoerg    }
105224139Sjoerg    else if (header_status == ON)
105324139Sjoerg    {
105424139Sjoerg	header_status = ERASE;
105524139Sjoerg    }
105624139Sjoerg}
105724139Sjoerg
105824139Sjoerg/*VARARGS2*/
1059300395Sngievoid
106024139Sjoergnew_message(type, msgfmt, a1, a2, a3)
106124139Sjoerg
106224139Sjoergint type;
106324139Sjoergchar *msgfmt;
106424139Sjoergcaddr_t a1, a2, a3;
106524139Sjoerg
106624139Sjoerg{
106724139Sjoerg    register int i;
106824139Sjoerg
106924139Sjoerg    /* first, format the message */
107066641Simp    (void) snprintf(next_msg, sizeof(next_msg), msgfmt, a1, a2, a3);
107124139Sjoerg
107224139Sjoerg    if (msglen > 0)
107324139Sjoerg    {
107424139Sjoerg	/* message there already -- can we clear it? */
107524139Sjoerg	if (!overstrike)
107624139Sjoerg	{
107724139Sjoerg	    /* yes -- write it and clear to end */
107824139Sjoerg	    i = strlen(next_msg);
107924139Sjoerg	    if ((type & MT_delayed) == 0)
108024139Sjoerg	    {
1081332948Slidl		type & MT_standout ? top_standout(next_msg) :
108224139Sjoerg		                     fputs(next_msg, stdout);
108324139Sjoerg		(void) clear_eol(msglen - i);
108424139Sjoerg		msglen = i;
108524139Sjoerg		next_msg[0] = '\0';
108624139Sjoerg	    }
108724139Sjoerg	}
108824139Sjoerg    }
108924139Sjoerg    else
109024139Sjoerg    {
109124139Sjoerg	if ((type & MT_delayed) == 0)
109224139Sjoerg	{
1093332948Slidl	    type & MT_standout ? top_standout(next_msg) : fputs(next_msg, stdout);
109424139Sjoerg	    msglen = strlen(next_msg);
109524139Sjoerg	    next_msg[0] = '\0';
109624139Sjoerg	}
109724139Sjoerg    }
109824139Sjoerg}
109924139Sjoerg
1100300395Sngievoid
110124139Sjoergclear_message()
110224139Sjoerg
110324139Sjoerg{
110424139Sjoerg    if (clear_eol(msglen) == 1)
110524139Sjoerg    {
110624139Sjoerg	putchar('\r');
110724139Sjoerg    }
110824139Sjoerg}
110924139Sjoerg
1110300395Sngieint
111124139Sjoergreadline(buffer, size, numeric)
111224139Sjoerg
111324139Sjoergchar *buffer;
111424139Sjoergint  size;
111524139Sjoergint  numeric;
111624139Sjoerg
111724139Sjoerg{
111824139Sjoerg    register char *ptr = buffer;
111924139Sjoerg    register char ch;
112024139Sjoerg    register char cnt = 0;
112124139Sjoerg    register char maxcnt = 0;
112224139Sjoerg
112324139Sjoerg    /* allow room for null terminator */
112424139Sjoerg    size -= 1;
112524139Sjoerg
112624139Sjoerg    /* read loop */
112724139Sjoerg    while ((fflush(stdout), read(0, ptr, 1) > 0))
112824139Sjoerg    {
112924139Sjoerg	/* newline means we are done */
113024142Sjoerg	if ((ch = *ptr) == '\n' || ch == '\r')
113124139Sjoerg	{
113224139Sjoerg	    break;
113324139Sjoerg	}
113424139Sjoerg
113524139Sjoerg	/* handle special editing characters */
113624139Sjoerg	if (ch == ch_kill)
113724139Sjoerg	{
113824139Sjoerg	    /* kill line -- account for overstriking */
113924139Sjoerg	    if (overstrike)
114024139Sjoerg	    {
114124139Sjoerg		msglen += maxcnt;
114224139Sjoerg	    }
114324139Sjoerg
114424139Sjoerg	    /* return null string */
114524139Sjoerg	    *buffer = '\0';
114624139Sjoerg	    putchar('\r');
114724139Sjoerg	    return(-1);
114824139Sjoerg	}
114924139Sjoerg	else if (ch == ch_erase)
115024139Sjoerg	{
115124139Sjoerg	    /* erase previous character */
115224139Sjoerg	    if (cnt <= 0)
115324139Sjoerg	    {
115424139Sjoerg		/* none to erase! */
115524139Sjoerg		putchar('\7');
115624139Sjoerg	    }
115724139Sjoerg	    else
115824139Sjoerg	    {
115924139Sjoerg		fputs("\b \b", stdout);
116024139Sjoerg		ptr--;
116124139Sjoerg		cnt--;
116224139Sjoerg	    }
116324139Sjoerg	}
116424139Sjoerg	/* check for character validity and buffer overflow */
116524139Sjoerg	else if (cnt == size || (numeric && !isdigit(ch)) ||
116624139Sjoerg		!isprint(ch))
116724139Sjoerg	{
116824139Sjoerg	    /* not legal */
116924139Sjoerg	    putchar('\7');
117024139Sjoerg	}
117124139Sjoerg	else
117224139Sjoerg	{
117324139Sjoerg	    /* echo it and store it in the buffer */
117424139Sjoerg	    putchar(ch);
117524139Sjoerg	    ptr++;
117624139Sjoerg	    cnt++;
117724139Sjoerg	    if (cnt > maxcnt)
117824139Sjoerg	    {
117924139Sjoerg		maxcnt = cnt;
118024139Sjoerg	    }
118124139Sjoerg	}
118224139Sjoerg    }
118324139Sjoerg
118424139Sjoerg    /* all done -- null terminate the string */
118524139Sjoerg    *ptr = '\0';
118624139Sjoerg
118724139Sjoerg    /* account for the extra characters in the message area */
118824139Sjoerg    /* (if terminal overstrikes, remember the furthest they went) */
118924139Sjoerg    msglen += overstrike ? maxcnt : cnt;
119024139Sjoerg
119124139Sjoerg    /* return either inputted number or string length */
119224139Sjoerg    putchar('\r');
119324139Sjoerg    return(cnt == 0 ? -1 : numeric ? atoi(buffer) : cnt);
119424139Sjoerg}
119524139Sjoerg
119624139Sjoerg/* internal support routines */
119724139Sjoerg
119824139Sjoergstatic int string_count(pp)
119924139Sjoerg
120024139Sjoergregister char **pp;
120124139Sjoerg
120224139Sjoerg{
120324139Sjoerg    register int cnt;
120424139Sjoerg
120524139Sjoerg    cnt = 0;
120624139Sjoerg    while (*pp++ != NULL)
120724139Sjoerg    {
120824139Sjoerg	cnt++;
120924139Sjoerg    }
121024139Sjoerg    return(cnt);
121124139Sjoerg}
121224139Sjoerg
121324139Sjoergstatic void summary_format(str, numbers, names)
121424139Sjoerg
121524139Sjoergchar *str;
121624139Sjoergint *numbers;
121724139Sjoergregister char **names;
121824139Sjoerg
121924139Sjoerg{
122024139Sjoerg    register char *p;
122124139Sjoerg    register int num;
122224139Sjoerg    register char *thisname;
122324139Sjoerg    register int useM = No;
1224318449Sallanjude    char rbuf[6];
122524139Sjoerg
122624139Sjoerg    /* format each number followed by its string */
122724139Sjoerg    p = str;
122824139Sjoerg    while ((thisname = *names++) != NULL)
122924139Sjoerg    {
123024139Sjoerg	/* get the number to format */
123124139Sjoerg	num = *numbers++;
123224139Sjoerg
123324139Sjoerg	/* display only non-zero numbers */
123424139Sjoerg	if (num > 0)
123524139Sjoerg	{
123624139Sjoerg	    /* is this number in kilobytes? */
123724139Sjoerg	    if (thisname[0] == 'K')
123824139Sjoerg	    {
123924139Sjoerg		/* yes: format it as a memory value */
124024139Sjoerg		p = strecpy(p, format_k(num));
124124139Sjoerg
124224139Sjoerg		/* skip over the K, since it was included by format_k */
124324139Sjoerg		p = strecpy(p, thisname+1);
124424139Sjoerg	    }
1245318449Sallanjude	    /* is this number a ratio? */
1246318449Sallanjude	    else if (thisname[0] == ':')
1247318449Sallanjude	    {
1248318449Sallanjude		(void) snprintf(rbuf, sizeof(rbuf), "%.2f",
1249318449Sallanjude		    (float)*(numbers - 2) / (float)num);
1250318449Sallanjude		p = strecpy(p, rbuf);
1251318449Sallanjude		p = strecpy(p, thisname);
1252318449Sallanjude	    }
125324139Sjoerg	    else
125424139Sjoerg	    {
125524139Sjoerg		p = strecpy(p, itoa(num));
125624139Sjoerg		p = strecpy(p, thisname);
125724139Sjoerg	    }
125824139Sjoerg	}
125924139Sjoerg
126024139Sjoerg	/* ignore negative numbers, but display corresponding string */
126124139Sjoerg	else if (num < 0)
126224139Sjoerg	{
126324139Sjoerg	    p = strecpy(p, thisname);
126424139Sjoerg	}
126524139Sjoerg    }
126624139Sjoerg
126724139Sjoerg    /* if the last two characters in the string are ", ", delete them */
126824139Sjoerg    p -= 2;
126924139Sjoerg    if (p >= str && p[0] == ',' && p[1] == ' ')
127024139Sjoerg    {
127124139Sjoerg	*p = '\0';
127224139Sjoerg    }
127324139Sjoerg}
127424139Sjoerg
127524139Sjoergstatic void line_update(old, new, start, line)
127624139Sjoerg
127724139Sjoergregister char *old;
127824139Sjoergregister char *new;
127924139Sjoergint start;
128024139Sjoergint line;
128124139Sjoerg
128224139Sjoerg{
128324139Sjoerg    register int ch;
128424139Sjoerg    register int diff;
128524139Sjoerg    register int newcol = start + 1;
128624139Sjoerg    register int lastcol = start;
128724139Sjoerg    char cursor_on_line = No;
128824139Sjoerg    char *current;
128924139Sjoerg
129024139Sjoerg    /* compare the two strings and only rewrite what has changed */
129124139Sjoerg    current = old;
129224139Sjoerg#ifdef DEBUG
129324139Sjoerg    fprintf(debug, "line_update, starting at %d\n", start);
129424139Sjoerg    fputs(old, debug);
129524139Sjoerg    fputc('\n', debug);
129624139Sjoerg    fputs(new, debug);
129724139Sjoerg    fputs("\n-\n", debug);
129824139Sjoerg#endif
129924139Sjoerg
130024139Sjoerg    /* start things off on the right foot		    */
130124139Sjoerg    /* this is to make sure the invariants get set up right */
130224139Sjoerg    if ((ch = *new++) != *old)
130324139Sjoerg    {
130424139Sjoerg	if (line - lastline == 1 && start == 0)
130524139Sjoerg	{
130624139Sjoerg	    putchar('\n');
130724139Sjoerg	}
130824139Sjoerg	else
130924139Sjoerg	{
131024139Sjoerg	    Move_to(start, line);
131124139Sjoerg	}
131224139Sjoerg	cursor_on_line = Yes;
131324139Sjoerg	putchar(ch);
131424139Sjoerg	*old = ch;
131524139Sjoerg	lastcol = 1;
131624139Sjoerg    }
131724139Sjoerg    old++;
131824139Sjoerg
131924139Sjoerg    /*
132024139Sjoerg     *  main loop -- check each character.  If the old and new aren't the
132124139Sjoerg     *	same, then update the display.  When the distance from the
132224139Sjoerg     *	current cursor position to the new change is small enough,
132324139Sjoerg     *	the characters that belong there are written to move the
132424139Sjoerg     *	cursor over.
132524139Sjoerg     *
132624139Sjoerg     *	Invariants:
132724139Sjoerg     *	    lastcol is the column where the cursor currently is sitting
132824139Sjoerg     *		(always one beyond the end of the last mismatch).
132924139Sjoerg     */
133024139Sjoerg    do		/* yes, a do...while */
133124139Sjoerg    {
133224139Sjoerg	if ((ch = *new++) != *old)
133324139Sjoerg	{
133424139Sjoerg	    /* new character is different from old	  */
133524139Sjoerg	    /* make sure the cursor is on top of this character */
133624139Sjoerg	    diff = newcol - lastcol;
133724139Sjoerg	    if (diff > 0)
133824139Sjoerg	    {
133924139Sjoerg		/* some motion is required--figure out which is shorter */
134024139Sjoerg		if (diff < 6 && cursor_on_line)
134124139Sjoerg		{
134224139Sjoerg		    /* overwrite old stuff--get it out of the old buffer */
134324139Sjoerg		    printf("%.*s", diff, &current[lastcol-start]);
134424139Sjoerg		}
134524139Sjoerg		else
134624139Sjoerg		{
134724139Sjoerg		    /* use cursor addressing */
134824139Sjoerg		    Move_to(newcol, line);
134924139Sjoerg		    cursor_on_line = Yes;
135024139Sjoerg		}
135124139Sjoerg		/* remember where the cursor is */
135224139Sjoerg		lastcol = newcol + 1;
135324139Sjoerg	    }
135424139Sjoerg	    else
135524139Sjoerg	    {
135624139Sjoerg		/* already there, update position */
135724139Sjoerg		lastcol++;
135824139Sjoerg	    }
135924139Sjoerg
136024139Sjoerg	    /* write what we need to */
136124139Sjoerg	    if (ch == '\0')
136224139Sjoerg	    {
136324139Sjoerg		/* at the end--terminate with a clear-to-end-of-line */
136424139Sjoerg		(void) clear_eol(strlen(old));
136524139Sjoerg	    }
136624139Sjoerg	    else
136724139Sjoerg	    {
136824139Sjoerg		/* write the new character */
136924139Sjoerg		putchar(ch);
137024139Sjoerg	    }
137124139Sjoerg	    /* put the new character in the screen buffer */
137224139Sjoerg	    *old = ch;
137324139Sjoerg	}
137424139Sjoerg
137524139Sjoerg	/* update working column and screen buffer pointer */
137624139Sjoerg	newcol++;
137724139Sjoerg	old++;
137824139Sjoerg
137924139Sjoerg    } while (ch != '\0');
138024139Sjoerg
138124139Sjoerg    /* zero out the rest of the line buffer -- MUST BE DONE! */
138224139Sjoerg    diff = display_width - newcol;
138324139Sjoerg    if (diff > 0)
138424139Sjoerg    {
138524139Sjoerg	memzero(old, diff);
138624139Sjoerg    }
138724139Sjoerg
138824139Sjoerg    /* remember where the current line is */
138924139Sjoerg    if (cursor_on_line)
139024139Sjoerg    {
139124139Sjoerg	lastline = line;
139224139Sjoerg    }
139324139Sjoerg}
139424139Sjoerg
139524139Sjoerg/*
139624139Sjoerg *  printable(str) - make the string pointed to by "str" into one that is
139724139Sjoerg *	printable (i.e.: all ascii), by converting all non-printable
139824139Sjoerg *	characters into '?'.  Replacements are done in place and a pointer
139924139Sjoerg *	to the original buffer is returned.
140024139Sjoerg */
140124139Sjoerg
140224139Sjoergchar *printable(str)
140324139Sjoerg
140424139Sjoergchar *str;
140524139Sjoerg
140624139Sjoerg{
140724139Sjoerg    register char *ptr;
140824139Sjoerg    register char ch;
140924139Sjoerg
141024139Sjoerg    ptr = str;
141124139Sjoerg    while ((ch = *ptr) != '\0')
141224139Sjoerg    {
141324139Sjoerg	if (!isprint(ch))
141424139Sjoerg	{
141524139Sjoerg	    *ptr = '?';
141624139Sjoerg	}
141724139Sjoerg	ptr++;
141824139Sjoerg    }
141924139Sjoerg    return(str);
142024139Sjoerg}
142142447Sobrien
1422300395Sngievoid
142342447Sobrieni_uptime(bt, tod)
142442447Sobrien
142542447Sobrienstruct timeval* bt;
142642447Sobrientime_t *tod;
142742447Sobrien
142842447Sobrien{
142942447Sobrien    time_t uptime;
143042447Sobrien    int days, hrs, mins, secs;
143142447Sobrien
143242447Sobrien    if (bt->tv_sec != -1) {
143342447Sobrien	uptime = *tod - bt->tv_sec;
143442447Sobrien	days = uptime / 86400;
143542447Sobrien	uptime %= 86400;
143642447Sobrien	hrs = uptime / 3600;
143742447Sobrien	uptime %= 3600;
143842447Sobrien	mins = uptime / 60;
143942447Sobrien	secs = uptime % 60;
144042447Sobrien
144142447Sobrien	/*
144242447Sobrien	 *  Display the uptime.
144342447Sobrien	 */
144442447Sobrien
144542447Sobrien	if (smart_terminal)
144642447Sobrien	{
144742447Sobrien	    Move_to((screen_width - 24) - (days > 9 ? 1 : 0), 0);
144842447Sobrien	}
144942447Sobrien	else
145042447Sobrien	{
145142447Sobrien	    fputs(" ", stdout);
145242447Sobrien	}
145342447Sobrien	printf(" up %d+%02d:%02d:%02d", days, hrs, mins, secs);
145442447Sobrien    }
145542447Sobrien}
1456