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$
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"
32301836Sngie
33301836Sngie#include <sys/time.h>
34301836Sngie
3524139Sjoerg#include <ctype.h>
3624139Sjoerg#include <time.h>
37301836Sngie#include <unistd.h>
3824139Sjoerg
3924139Sjoerg#include "screen.h"		/* interface to screen package */
4024139Sjoerg#include "layout.h"		/* defines for screen position layout */
4124139Sjoerg#include "display.h"
4224139Sjoerg#include "top.h"
4324139Sjoerg#include "top.local.h"
4424139Sjoerg#include "boolean.h"
4524139Sjoerg#include "machine.h"		/* we should eliminate this!!! */
4624139Sjoerg#include "utils.h"
4724139Sjoerg
4824139Sjoerg#ifdef DEBUG
4924139SjoergFILE *debug;
5024139Sjoerg#endif
5124139Sjoerg
5224139Sjoerg/* imported from screen.c */
5324139Sjoergextern int overstrike;
5424139Sjoerg
5524139Sjoergstatic int lmpid = 0;
5624139Sjoergstatic int last_hi = 0;		/* used in u_process and u_endscreen */
5724139Sjoergstatic int lastline = 0;
5824139Sjoergstatic int display_width = MAX_COLS;
5924139Sjoerg
6024139Sjoerg#define lineindex(l) ((l)*display_width)
6124139Sjoerg
6224139Sjoerg
6324139Sjoerg/* things initialized by display_init and used thruout */
6424139Sjoerg
6524139Sjoerg/* buffer of proc information lines for display updating */
6624139Sjoergchar *screenbuf = NULL;
6724139Sjoerg
6824139Sjoergstatic char **procstate_names;
6924139Sjoergstatic char **cpustate_names;
7024139Sjoergstatic char **memory_names;
71237656Sjhbstatic char **arc_names;
7224142Sjoergstatic char **swap_names;
7324139Sjoerg
7424139Sjoergstatic int num_procstates;
7524139Sjoergstatic int num_cpustates;
7624139Sjoergstatic int num_memory;
7724142Sjoergstatic int num_swap;
7824139Sjoerg
7924139Sjoergstatic int *lprocstates;
8024139Sjoergstatic int *lcpustates;
8124139Sjoergstatic int *lmemory;
8224142Sjoergstatic int *lswap;
8324139Sjoerg
84175420Speterstatic int num_cpus;
8524139Sjoergstatic int *cpustate_columns;
8624139Sjoergstatic int cpustate_total_length;
87175420Speterstatic int cpustates_column;
8824139Sjoerg
8924139Sjoergstatic enum { OFF, ON, ERASE } header_status = ON;
9024139Sjoerg
9124139Sjoergstatic int string_count();
9224139Sjoergstatic void summary_format();
9324139Sjoergstatic void line_update();
9424139Sjoerg
95175420Speterint  x_lastpid =	10;
96175420Speterint  y_lastpid =	0;
97175420Speterint  x_loadave =	33;
98175420Speterint  x_loadave_nompid =	15;
99175420Speterint  y_loadave =	0;
100175420Speterint  x_procstate =	0;
101175420Speterint  y_procstate =	1;
102175420Speterint  x_brkdn =		15;
103175420Speterint  y_brkdn =		1;
104175420Speterint  x_mem =		5;
105175420Speterint  y_mem =		3;
106237656Sjhbint  x_arc =		5;
107237656Sjhbint  y_arc =		4;
108175420Speterint  x_swap =		6;
109175420Speterint  y_swap =		4;
110175420Speterint  y_message =	5;
111175420Speterint  x_header =		0;
112175420Speterint  y_header =		6;
113175420Speterint  x_idlecursor =	0;
114175420Speterint  y_idlecursor =	5;
115175420Speterint  y_procs =		7;
116175420Speter
117175420Speterint  y_cpustates =	2;
118175420Speterint  Header_lines =	7;
119175420Speter
12024139Sjoergint display_resize()
12124139Sjoerg
12224139Sjoerg{
12324139Sjoerg    register int lines;
12424139Sjoerg
12524139Sjoerg    /* first, deallocate any previous buffer that may have been there */
12624139Sjoerg    if (screenbuf != NULL)
12724139Sjoerg    {
12824139Sjoerg	free(screenbuf);
12924139Sjoerg    }
13024139Sjoerg
13124139Sjoerg    /* calculate the current dimensions */
13224139Sjoerg    /* if operating in "dumb" mode, we only need one line */
13324139Sjoerg    lines = smart_terminal ? screen_length - Header_lines : 1;
13424139Sjoerg
135101692Sdwmalone    if (lines < 0)
136101692Sdwmalone	lines = 0;
13724139Sjoerg    /* we don't want more than MAX_COLS columns, since the machine-dependent
13824139Sjoerg       modules make static allocations based on MAX_COLS and we don't want
13924139Sjoerg       to run off the end of their buffers */
14024139Sjoerg    display_width = screen_width;
14124139Sjoerg    if (display_width >= MAX_COLS)
14224139Sjoerg    {
14324139Sjoerg	display_width = MAX_COLS - 1;
14424139Sjoerg    }
14524139Sjoerg
14624139Sjoerg    /* now, allocate space for the screen buffer */
14724139Sjoerg    screenbuf = (char *)malloc(lines * display_width);
14824139Sjoerg    if (screenbuf == (char *)NULL)
14924139Sjoerg    {
15024139Sjoerg	/* oops! */
15124139Sjoerg	return(-1);
15224139Sjoerg    }
15324139Sjoerg
15424139Sjoerg    /* return number of lines available */
15524139Sjoerg    /* for dumb terminals, pretend like we can show any amount */
15624139Sjoerg    return(smart_terminal ? lines : Largest);
15724139Sjoerg}
15824139Sjoerg
159223936Sjhbint display_updatecpus(statics)
16024139Sjoerg
16124139Sjoergstruct statics *statics;
16224139Sjoerg
16324139Sjoerg{
164224205Sjhb    register int *lp;
16524139Sjoerg    register int lines;
16624139Sjoerg    register int i;
167223936Sjhb
16824139Sjoerg    /* call resize to do the dirty work */
16924139Sjoerg    lines = display_resize();
170224205Sjhb    if (pcpu_stats)
171224205Sjhb	num_cpus = statics->ncpus;
172224205Sjhb    else
173224205Sjhb	num_cpus = 1;
174175420Speter    cpustates_column = 5;	/* CPU: */
175175420Speter    if (num_cpus != 1)
176175420Speter    cpustates_column += 2;	/* CPU 0: */
177175420Speter    for (i = num_cpus; i > 9; i /= 10)
178175420Speter	cpustates_column++;
17924139Sjoerg
180224205Sjhb    /* fill the "last" array with all -1s, to insure correct updating */
181224205Sjhb    lp = lcpustates;
182224205Sjhb    i = num_cpustates * num_cpus;
183224205Sjhb    while (--i >= 0)
184224205Sjhb    {
185224205Sjhb	*lp++ = -1;
186224205Sjhb    }
187224205Sjhb
188223936Sjhb    return(lines);
189223936Sjhb}
190223936Sjhb
191223936Sjhbint display_init(statics)
192223936Sjhb
193223936Sjhbstruct statics *statics;
194223936Sjhb
195223936Sjhb{
196223936Sjhb    register int lines;
197223936Sjhb    register char **pp;
198223936Sjhb    register int *ip;
199223936Sjhb    register int i;
200223936Sjhb
201223936Sjhb    lines = display_updatecpus(statics);
202223936Sjhb
20324139Sjoerg    /* only do the rest if we need to */
20424139Sjoerg    if (lines > -1)
20524139Sjoerg    {
20624139Sjoerg	/* save pointers and allocate space for names */
20724139Sjoerg	procstate_names = statics->procstate_names;
20824139Sjoerg	num_procstates = string_count(procstate_names);
20924139Sjoerg	lprocstates = (int *)malloc(num_procstates * sizeof(int));
21024139Sjoerg
21124139Sjoerg	cpustate_names = statics->cpustate_names;
21224142Sjoerg
21324142Sjoerg	swap_names = statics->swap_names;
21424142Sjoerg	num_swap = string_count(swap_names);
21524142Sjoerg	lswap = (int *)malloc(num_swap * sizeof(int));
21624139Sjoerg	num_cpustates = string_count(cpustate_names);
217224205Sjhb	lcpustates = (int *)malloc(num_cpustates * sizeof(int) * statics->ncpus);
21824139Sjoerg	cpustate_columns = (int *)malloc(num_cpustates * sizeof(int));
21924139Sjoerg
22024139Sjoerg	memory_names = statics->memory_names;
22124139Sjoerg	num_memory = string_count(memory_names);
22224139Sjoerg	lmemory = (int *)malloc(num_memory * sizeof(int));
22324139Sjoerg
224237656Sjhb	arc_names = statics->arc_names;
225237656Sjhb
22624139Sjoerg	/* calculate starting columns where needed */
22724139Sjoerg	cpustate_total_length = 0;
22824139Sjoerg	pp = cpustate_names;
22924139Sjoerg	ip = cpustate_columns;
23024139Sjoerg	while (*pp != NULL)
23124139Sjoerg	{
23289758Sdwmalone	    *ip++ = cpustate_total_length;
23324139Sjoerg	    if ((i = strlen(*pp++)) > 0)
23424139Sjoerg	    {
23524139Sjoerg		cpustate_total_length += i + 8;
23624139Sjoerg	    }
23724139Sjoerg	}
23824139Sjoerg    }
23924139Sjoerg
24024139Sjoerg    /* return number of lines available */
24124139Sjoerg    return(lines);
24224139Sjoerg}
24324139Sjoerg
244301836Sngievoid
24524139Sjoergi_loadave(mpid, avenrun)
24624139Sjoerg
24724139Sjoergint mpid;
24824139Sjoergdouble *avenrun;
24924139Sjoerg
25024139Sjoerg{
25124139Sjoerg    register int i;
25224139Sjoerg
25324139Sjoerg    /* i_loadave also clears the screen, since it is first */
25424139Sjoerg    clear();
25524139Sjoerg
25624139Sjoerg    /* mpid == -1 implies this system doesn't have an _mpid */
25724139Sjoerg    if (mpid != -1)
25824139Sjoerg    {
25924139Sjoerg	printf("last pid: %5d;  ", mpid);
26024139Sjoerg    }
26124139Sjoerg
26224139Sjoerg    printf("load averages");
26324139Sjoerg
26424139Sjoerg    for (i = 0; i < 3; i++)
26524139Sjoerg    {
26624139Sjoerg	printf("%c %5.2f",
26724139Sjoerg	    i == 0 ? ':' : ',',
26824139Sjoerg	    avenrun[i]);
26924139Sjoerg    }
27024139Sjoerg    lmpid = mpid;
27124139Sjoerg}
27224139Sjoerg
273301836Sngievoid
27424139Sjoergu_loadave(mpid, avenrun)
27524139Sjoerg
27624139Sjoergint mpid;
27724139Sjoergdouble *avenrun;
27824139Sjoerg
27924139Sjoerg{
28024139Sjoerg    register int i;
28124139Sjoerg
28224139Sjoerg    if (mpid != -1)
28324139Sjoerg    {
28424139Sjoerg	/* change screen only when value has really changed */
28524139Sjoerg	if (mpid != lmpid)
28624139Sjoerg	{
28724139Sjoerg	    Move_to(x_lastpid, y_lastpid);
28824139Sjoerg	    printf("%5d", mpid);
28924139Sjoerg	    lmpid = mpid;
29024139Sjoerg	}
29124139Sjoerg
29224139Sjoerg	/* i remembers x coordinate to move to */
29324139Sjoerg	i = x_loadave;
29424139Sjoerg    }
29524139Sjoerg    else
29624139Sjoerg    {
29724139Sjoerg	i = x_loadave_nompid;
29824139Sjoerg    }
29924139Sjoerg
30024139Sjoerg    /* move into position for load averages */
30124139Sjoerg    Move_to(i, y_loadave);
30224139Sjoerg
30324139Sjoerg    /* display new load averages */
30424139Sjoerg    /* we should optimize this and only display changes */
30524139Sjoerg    for (i = 0; i < 3; i++)
30624139Sjoerg    {
30724139Sjoerg	printf("%s%5.2f",
30824139Sjoerg	    i == 0 ? "" : ", ",
30924139Sjoerg	    avenrun[i]);
31024139Sjoerg    }
31124139Sjoerg}
31224139Sjoerg
313301836Sngievoid
31424139Sjoergi_timeofday(tod)
31524139Sjoerg
31624139Sjoergtime_t *tod;
31724139Sjoerg
31824139Sjoerg{
31924139Sjoerg    /*
32024139Sjoerg     *  Display the current time.
32124139Sjoerg     *  "ctime" always returns a string that looks like this:
32224139Sjoerg     *
32324139Sjoerg     *	Sun Sep 16 01:03:52 1973
32424139Sjoerg     *      012345678901234567890123
32524139Sjoerg     *	          1         2
32624139Sjoerg     *
32724139Sjoerg     *  We want indices 11 thru 18 (length 8).
32824139Sjoerg     */
32924139Sjoerg
33024139Sjoerg    if (smart_terminal)
33124139Sjoerg    {
33224139Sjoerg	Move_to(screen_width - 8, 0);
33324139Sjoerg    }
33424139Sjoerg    else
33524139Sjoerg    {
33624139Sjoerg	fputs("    ", stdout);
33724139Sjoerg    }
33824139Sjoerg#ifdef DEBUG
33924139Sjoerg    {
34024139Sjoerg	char *foo;
34124139Sjoerg	foo = ctime(tod);
34224139Sjoerg	fputs(foo, stdout);
34324139Sjoerg    }
34424139Sjoerg#endif
34524139Sjoerg    printf("%-8.8s\n", &(ctime(tod)[11]));
34624139Sjoerg    lastline = 1;
34724139Sjoerg}
34824139Sjoerg
34924139Sjoergstatic int ltotal = 0;
35089758Sdwmalonestatic char procstates_buffer[MAX_COLS];
35124139Sjoerg
35224139Sjoerg/*
35324139Sjoerg *  *_procstates(total, brkdn, names) - print the process summary line
35424139Sjoerg *
35524139Sjoerg *  Assumptions:  cursor is at the beginning of the line on entry
35624139Sjoerg *		  lastline is valid
35724139Sjoerg */
35824139Sjoerg
359301836Sngievoid
36024139Sjoergi_procstates(total, brkdn)
36124139Sjoerg
36224139Sjoergint total;
36324139Sjoergint *brkdn;
36424139Sjoerg
36524139Sjoerg{
36624139Sjoerg    register int i;
36724139Sjoerg
36824139Sjoerg    /* write current number of processes and remember the value */
36924139Sjoerg    printf("%d processes:", total);
37024139Sjoerg    ltotal = total;
37124139Sjoerg
37224139Sjoerg    /* put out enough spaces to get to column 15 */
37324139Sjoerg    i = digits(total);
37424139Sjoerg    while (i++ < 4)
37524139Sjoerg    {
37624139Sjoerg	putchar(' ');
37724139Sjoerg    }
37824139Sjoerg
37924139Sjoerg    /* format and print the process state summary */
38024139Sjoerg    summary_format(procstates_buffer, brkdn, procstate_names);
38124139Sjoerg    fputs(procstates_buffer, stdout);
38224139Sjoerg
38324139Sjoerg    /* save the numbers for next time */
38424139Sjoerg    memcpy(lprocstates, brkdn, num_procstates * sizeof(int));
38524139Sjoerg}
38624139Sjoerg
387301836Sngievoid
38824139Sjoergu_procstates(total, brkdn)
38924139Sjoerg
39024139Sjoergint total;
39124139Sjoergint *brkdn;
39224139Sjoerg
39324139Sjoerg{
39489758Sdwmalone    static char new[MAX_COLS];
39524139Sjoerg    register int i;
39624139Sjoerg
39724139Sjoerg    /* update number of processes only if it has changed */
39824139Sjoerg    if (ltotal != total)
39924139Sjoerg    {
40024139Sjoerg	/* move and overwrite */
40124139Sjoerg#if (x_procstate == 0)
40224139Sjoerg	Move_to(x_procstate, y_procstate);
40324139Sjoerg#else
40424139Sjoerg	/* cursor is already there...no motion needed */
40524139Sjoerg	/* assert(lastline == 1); */
40624139Sjoerg#endif
40724139Sjoerg	printf("%d", total);
40824139Sjoerg
40924139Sjoerg	/* if number of digits differs, rewrite the label */
41024139Sjoerg	if (digits(total) != digits(ltotal))
41124139Sjoerg	{
41224139Sjoerg	    fputs(" processes:", stdout);
41324139Sjoerg	    /* put out enough spaces to get to column 15 */
41424139Sjoerg	    i = digits(total);
41524139Sjoerg	    while (i++ < 4)
41624139Sjoerg	    {
41724139Sjoerg		putchar(' ');
41824139Sjoerg	    }
41924139Sjoerg	    /* cursor may end up right where we want it!!! */
42024139Sjoerg	}
42124139Sjoerg
42224139Sjoerg	/* save new total */
42324139Sjoerg	ltotal = total;
42424139Sjoerg    }
42524139Sjoerg
42624139Sjoerg    /* see if any of the state numbers has changed */
42724139Sjoerg    if (memcmp(lprocstates, brkdn, num_procstates * sizeof(int)) != 0)
42824139Sjoerg    {
42924139Sjoerg	/* format and update the line */
43024139Sjoerg	summary_format(new, brkdn, procstate_names);
43124139Sjoerg	line_update(procstates_buffer, new, x_brkdn, y_brkdn);
43224139Sjoerg	memcpy(lprocstates, brkdn, num_procstates * sizeof(int));
43324139Sjoerg    }
43424139Sjoerg}
43524139Sjoerg
436175420Speter#ifdef no_more
43724139Sjoerg/*
43824139Sjoerg *  *_cpustates(states, names) - print the cpu state percentages
43924139Sjoerg *
44024139Sjoerg *  Assumptions:  cursor is on the PREVIOUS line
44124139Sjoerg */
44224139Sjoerg
44324139Sjoerg/* cpustates_tag() calculates the correct tag to use to label the line */
44424139Sjoerg
44524139Sjoergchar *cpustates_tag()
44624139Sjoerg
44724139Sjoerg{
44824139Sjoerg    register char *use;
44924139Sjoerg
45024139Sjoerg    static char *short_tag = "CPU: ";
45124139Sjoerg    static char *long_tag = "CPU states: ";
45224139Sjoerg
45324139Sjoerg    /* if length + strlen(long_tag) >= screen_width, then we have to
45424139Sjoerg       use the shorter tag (we subtract 2 to account for ": ") */
45524139Sjoerg    if (cpustate_total_length + (int)strlen(long_tag) - 2 >= screen_width)
45624139Sjoerg    {
45724139Sjoerg	use = short_tag;
45824139Sjoerg    }
45924139Sjoerg    else
46024139Sjoerg    {
46124139Sjoerg	use = long_tag;
46224139Sjoerg    }
46324139Sjoerg
46424139Sjoerg    /* set cpustates_column accordingly then return result */
46524139Sjoerg    cpustates_column = strlen(use);
46624139Sjoerg    return(use);
46724139Sjoerg}
468175420Speter#endif
46924139Sjoerg
470301836Sngievoid
47124139Sjoergi_cpustates(states)
47224139Sjoerg
473301836Sngieint *states;
47424139Sjoerg
47524139Sjoerg{
47624139Sjoerg    register int i = 0;
47724139Sjoerg    register int value;
478175420Speter    register char **names;
47924139Sjoerg    register char *thisname;
480175420Speter    int cpu;
48124139Sjoerg
482175420Speterfor (cpu = 0; cpu < num_cpus; cpu++) {
483175420Speter    names = cpustate_names;
484175420Speter
48524139Sjoerg    /* print tag and bump lastline */
486175420Speter    if (num_cpus == 1)
487175420Speter	printf("\nCPU: ");
488218171Sjhb    else {
489218171Sjhb	value = printf("\nCPU %d: ", cpu);
490218171Sjhb	while (value++ <= cpustates_column)
491218171Sjhb		printf(" ");
492218171Sjhb    }
49324139Sjoerg    lastline++;
49424139Sjoerg
49524139Sjoerg    /* now walk thru the names and print the line */
49624139Sjoerg    while ((thisname = *names++) != NULL)
49724139Sjoerg    {
49824139Sjoerg	if (*thisname != '\0')
49924139Sjoerg	{
50024139Sjoerg	    /* retrieve the value and remember it */
50124139Sjoerg	    value = *states++;
50224139Sjoerg
50324139Sjoerg	    /* if percentage is >= 1000, print it as 100% */
50424139Sjoerg	    printf((value >= 1000 ? "%s%4.0f%% %s" : "%s%4.1f%% %s"),
505175420Speter		   (i++ % num_cpustates) == 0 ? "" : ", ",
50624139Sjoerg		   ((float)value)/10.,
50724139Sjoerg		   thisname);
50824139Sjoerg	}
50924139Sjoerg    }
510175420Speter}
51124139Sjoerg
51224139Sjoerg    /* copy over values into "last" array */
513175420Speter    memcpy(lcpustates, states, num_cpustates * sizeof(int) * num_cpus);
51424139Sjoerg}
51524139Sjoerg
516301836Sngievoid
51724139Sjoergu_cpustates(states)
51824139Sjoerg
519301836Sngieint *states;
52024139Sjoerg
52124139Sjoerg{
52224139Sjoerg    register int value;
523175420Speter    register char **names;
52424139Sjoerg    register char *thisname;
52524139Sjoerg    register int *lp;
52624139Sjoerg    register int *colp;
527175420Speter    int cpu;
52824139Sjoerg
529175420Speterfor (cpu = 0; cpu < num_cpus; cpu++) {
530175420Speter    names = cpustate_names;
531175420Speter
532175420Speter    Move_to(cpustates_column, y_cpustates + cpu);
533175420Speter    lastline = y_cpustates + cpu;
534175420Speter    lp = lcpustates + (cpu * num_cpustates);
53524139Sjoerg    colp = cpustate_columns;
53624139Sjoerg
53724139Sjoerg    /* we could be much more optimal about this */
53824139Sjoerg    while ((thisname = *names++) != NULL)
53924139Sjoerg    {
54024139Sjoerg	if (*thisname != '\0')
54124139Sjoerg	{
54224139Sjoerg	    /* did the value change since last time? */
54324139Sjoerg	    if (*lp != *states)
54424139Sjoerg	    {
54524139Sjoerg		/* yes, move and change */
546175420Speter		Move_to(cpustates_column + *colp, y_cpustates + cpu);
547175420Speter		lastline = y_cpustates + cpu;
54824139Sjoerg
54924139Sjoerg		/* retrieve value and remember it */
55024139Sjoerg		value = *states;
55124139Sjoerg
55224139Sjoerg		/* if percentage is >= 1000, print it as 100% */
55324139Sjoerg		printf((value >= 1000 ? "%4.0f" : "%4.1f"),
55424139Sjoerg		       ((double)value)/10.);
55524139Sjoerg
55624139Sjoerg		/* remember it for next time */
55789758Sdwmalone		*lp = value;
55824139Sjoerg	    }
55924139Sjoerg	}
56024139Sjoerg
56124139Sjoerg	/* increment and move on */
56224139Sjoerg	lp++;
56324139Sjoerg	states++;
56424139Sjoerg	colp++;
56524139Sjoerg    }
56624139Sjoerg}
567175420Speter}
56824139Sjoerg
569301836Sngievoid
57024139Sjoergz_cpustates()
57124139Sjoerg
57224139Sjoerg{
57324139Sjoerg    register int i = 0;
574175420Speter    register char **names;
57524139Sjoerg    register char *thisname;
57624139Sjoerg    register int *lp;
577218171Sjhb    int cpu, value;
57824139Sjoerg
579175420Speterfor (cpu = 0; cpu < num_cpus; cpu++) {
580175420Speter    names = cpustate_names;
581175420Speter
58224139Sjoerg    /* show tag and bump lastline */
583175420Speter    if (num_cpus == 1)
584175420Speter	printf("\nCPU: ");
585218171Sjhb    else {
586218171Sjhb	value = printf("\nCPU %d: ", cpu);
587218171Sjhb	while (value++ <= cpustates_column)
588218171Sjhb		printf(" ");
589218171Sjhb    }
59024139Sjoerg    lastline++;
59124139Sjoerg
59224139Sjoerg    while ((thisname = *names++) != NULL)
59324139Sjoerg    {
59424139Sjoerg	if (*thisname != '\0')
59524139Sjoerg	{
596175420Speter	    printf("%s    %% %s", (i++ % num_cpustates) == 0 ? "" : ", ", thisname);
59724139Sjoerg	}
59824139Sjoerg    }
599175420Speter}
60024139Sjoerg
60124139Sjoerg    /* fill the "last" array with all -1s, to insure correct updating */
60224139Sjoerg    lp = lcpustates;
603175420Speter    i = num_cpustates * num_cpus;
60424139Sjoerg    while (--i >= 0)
60524139Sjoerg    {
60624139Sjoerg	*lp++ = -1;
60724139Sjoerg    }
60824139Sjoerg}
60924139Sjoerg
61024139Sjoerg/*
61124139Sjoerg *  *_memory(stats) - print "Memory: " followed by the memory summary string
61224139Sjoerg *
61324139Sjoerg *  Assumptions:  cursor is on "lastline"
61424139Sjoerg *                for i_memory ONLY: cursor is on the previous line
61524139Sjoerg */
61624139Sjoerg
61724139Sjoergchar memory_buffer[MAX_COLS];
61824139Sjoerg
619301836Sngievoid
62024139Sjoergi_memory(stats)
62124139Sjoerg
62224139Sjoergint *stats;
62324139Sjoerg
62424139Sjoerg{
62524142Sjoerg    fputs("\nMem: ", stdout);
62624139Sjoerg    lastline++;
62724139Sjoerg
62824139Sjoerg    /* format and print the memory summary */
62924139Sjoerg    summary_format(memory_buffer, stats, memory_names);
63024139Sjoerg    fputs(memory_buffer, stdout);
63124139Sjoerg}
63224139Sjoerg
633301836Sngievoid
63424139Sjoergu_memory(stats)
63524139Sjoerg
63624139Sjoergint *stats;
63724139Sjoerg
63824139Sjoerg{
63924139Sjoerg    static char new[MAX_COLS];
64024139Sjoerg
64124139Sjoerg    /* format the new line */
64224139Sjoerg    summary_format(new, stats, memory_names);
64324139Sjoerg    line_update(memory_buffer, new, x_mem, y_mem);
64424139Sjoerg}
64524139Sjoerg
64624139Sjoerg/*
647237656Sjhb *  *_arc(stats) - print "ARC: " followed by the ARC summary string
648237656Sjhb *
649237656Sjhb *  Assumptions:  cursor is on "lastline"
650237656Sjhb *                for i_arc ONLY: cursor is on the previous line
651237656Sjhb */
652237656Sjhbchar arc_buffer[MAX_COLS];
653237656Sjhb
654301836Sngievoid
655237656Sjhbi_arc(stats)
656237656Sjhb
657237656Sjhbint *stats;
658237656Sjhb
659237656Sjhb{
660237656Sjhb    if (arc_names == NULL)
661301836Sngie	return;
662237656Sjhb
663237656Sjhb    fputs("\nARC: ", stdout);
664237656Sjhb    lastline++;
665237656Sjhb
666237656Sjhb    /* format and print the memory summary */
667237656Sjhb    summary_format(arc_buffer, stats, arc_names);
668237656Sjhb    fputs(arc_buffer, stdout);
669237656Sjhb}
670237656Sjhb
671301836Sngievoid
672237656Sjhbu_arc(stats)
673237656Sjhb
674237656Sjhbint *stats;
675237656Sjhb
676237656Sjhb{
677237656Sjhb    static char new[MAX_COLS];
678237656Sjhb
679237656Sjhb    if (arc_names == NULL)
680301836Sngie	return;
681237656Sjhb
682237656Sjhb    /* format the new line */
683237656Sjhb    summary_format(new, stats, arc_names);
684237656Sjhb    line_update(arc_buffer, new, x_arc, y_arc);
685237656Sjhb}
686237656Sjhb
687237656Sjhb
688237656Sjhb/*
68924142Sjoerg *  *_swap(stats) - print "Swap: " followed by the swap summary string
69024142Sjoerg *
69124142Sjoerg *  Assumptions:  cursor is on "lastline"
69224142Sjoerg *                for i_swap ONLY: cursor is on the previous line
69324142Sjoerg */
69424142Sjoerg
69524142Sjoergchar swap_buffer[MAX_COLS];
69624142Sjoerg
697301836Sngievoid
69824142Sjoergi_swap(stats)
69924142Sjoerg
70024142Sjoergint *stats;
70124142Sjoerg
70224142Sjoerg{
70324142Sjoerg    fputs("\nSwap: ", stdout);
70424142Sjoerg    lastline++;
70524142Sjoerg
70624142Sjoerg    /* format and print the swap summary */
70724142Sjoerg    summary_format(swap_buffer, stats, swap_names);
70824142Sjoerg    fputs(swap_buffer, stdout);
70924142Sjoerg}
71024142Sjoerg
711301836Sngievoid
71224142Sjoergu_swap(stats)
71324142Sjoerg
71424142Sjoergint *stats;
71524142Sjoerg
71624142Sjoerg{
71724142Sjoerg    static char new[MAX_COLS];
71824142Sjoerg
71924142Sjoerg    /* format the new line */
72024142Sjoerg    summary_format(new, stats, swap_names);
72124142Sjoerg    line_update(swap_buffer, new, x_swap, y_swap);
72224142Sjoerg}
72324142Sjoerg
72424142Sjoerg/*
72524139Sjoerg *  *_message() - print the next pending message line, or erase the one
72624139Sjoerg *                that is there.
72724139Sjoerg *
72824139Sjoerg *  Note that u_message is (currently) the same as i_message.
72924139Sjoerg *
73024139Sjoerg *  Assumptions:  lastline is consistent
73124139Sjoerg */
73224139Sjoerg
73324139Sjoerg/*
73424139Sjoerg *  i_message is funny because it gets its message asynchronously (with
73524139Sjoerg *	respect to screen updates).
73624139Sjoerg */
73724139Sjoerg
73824139Sjoergstatic char next_msg[MAX_COLS + 5];
73924139Sjoergstatic int msglen = 0;
74024139Sjoerg/* Invariant: msglen is always the length of the message currently displayed
74124139Sjoerg   on the screen (even when next_msg doesn't contain that message). */
74224139Sjoerg
743301836Sngievoid
74424139Sjoergi_message()
74524139Sjoerg
74624139Sjoerg{
74724139Sjoerg    while (lastline < y_message)
74824139Sjoerg    {
74924139Sjoerg	fputc('\n', stdout);
75024139Sjoerg	lastline++;
75124139Sjoerg    }
75224139Sjoerg    if (next_msg[0] != '\0')
75324139Sjoerg    {
75424139Sjoerg	standout(next_msg);
75524139Sjoerg	msglen = strlen(next_msg);
75624139Sjoerg	next_msg[0] = '\0';
75724139Sjoerg    }
75824139Sjoerg    else if (msglen > 0)
75924139Sjoerg    {
76024139Sjoerg	(void) clear_eol(msglen);
76124139Sjoerg	msglen = 0;
76224139Sjoerg    }
76324139Sjoerg}
76424139Sjoerg
765301836Sngievoid
76624139Sjoergu_message()
76724139Sjoerg
76824139Sjoerg{
76924139Sjoerg    i_message();
77024139Sjoerg}
77124139Sjoerg
77224139Sjoergstatic int header_length;
77324139Sjoerg
77424139Sjoerg/*
775146344Skeramida * Trim a header string to the current display width and return a newly
776146344Skeramida * allocated area with the trimmed header.
777146344Skeramida */
778146344Skeramida
779146344Skeramidachar *
780146344Skeramidatrim_header(text)
781146344Skeramida
782146344Skeramidachar *text;
783146344Skeramida
784146344Skeramida{
785146344Skeramida	char *s;
786146344Skeramida	int width;
787146344Skeramida
788146344Skeramida	s = NULL;
789223342Sdelphij	width = display_width;
790146344Skeramida	header_length = strlen(text);
791146344Skeramida	if (header_length >= width) {
792146344Skeramida		s = malloc((width + 1) * sizeof(char));
793146344Skeramida		if (s == NULL)
794146344Skeramida			return (NULL);
795146344Skeramida		strncpy(s, text, width);
796146344Skeramida		s[width] = '\0';
797146344Skeramida	}
798146344Skeramida	return (s);
799146344Skeramida}
800146344Skeramida
801146344Skeramida/*
80224139Sjoerg *  *_header(text) - print the header for the process area
80324139Sjoerg *
80424139Sjoerg *  Assumptions:  cursor is on the previous line and lastline is consistent
80524139Sjoerg */
80624139Sjoerg
807301836Sngievoid
80824139Sjoergi_header(text)
80924139Sjoerg
81024139Sjoergchar *text;
81124139Sjoerg
81224139Sjoerg{
813146344Skeramida    char *s;
814146344Skeramida
815146344Skeramida    s = trim_header(text);
816146344Skeramida    if (s != NULL)
817146344Skeramida	text = s;
818146344Skeramida
81924139Sjoerg    if (header_status == ON)
82024139Sjoerg    {
82124139Sjoerg	putchar('\n');
822223342Sdelphij	fputs(text, stdout);
82324139Sjoerg	lastline++;
82424139Sjoerg    }
82524139Sjoerg    else if (header_status == ERASE)
82624139Sjoerg    {
82724139Sjoerg	header_status = OFF;
82824139Sjoerg    }
829146344Skeramida    free(s);
83024139Sjoerg}
83124139Sjoerg
83224139Sjoerg/*ARGSUSED*/
833301836Sngievoid
83424139Sjoergu_header(text)
83524139Sjoerg
836301836Sngiechar *text __unused;		/* ignored */
83724139Sjoerg
83824139Sjoerg{
839146344Skeramida
84024139Sjoerg    if (header_status == ERASE)
84124139Sjoerg    {
84224139Sjoerg	putchar('\n');
84324139Sjoerg	lastline++;
84424139Sjoerg	clear_eol(header_length);
84524139Sjoerg	header_status = OFF;
84624139Sjoerg    }
84724139Sjoerg}
84824139Sjoerg
84924139Sjoerg/*
85024139Sjoerg *  *_process(line, thisline) - print one process line
85124139Sjoerg *
85224139Sjoerg *  Assumptions:  lastline is consistent
85324139Sjoerg */
85424139Sjoerg
855301836Sngievoid
85624139Sjoergi_process(line, thisline)
85724139Sjoerg
85824139Sjoergint line;
85924139Sjoergchar *thisline;
86024139Sjoerg
86124139Sjoerg{
86224139Sjoerg    register char *p;
86324139Sjoerg    register char *base;
86424139Sjoerg
86524139Sjoerg    /* make sure we are on the correct line */
86624139Sjoerg    while (lastline < y_procs + line)
86724139Sjoerg    {
86824139Sjoerg	putchar('\n');
86924139Sjoerg	lastline++;
87024139Sjoerg    }
87124139Sjoerg
87224139Sjoerg    /* truncate the line to conform to our current screen width */
87324139Sjoerg    thisline[display_width] = '\0';
87424139Sjoerg
87524139Sjoerg    /* write the line out */
87624139Sjoerg    fputs(thisline, stdout);
87724139Sjoerg
87824139Sjoerg    /* copy it in to our buffer */
87924139Sjoerg    base = smart_terminal ? screenbuf + lineindex(line) : screenbuf;
88024139Sjoerg    p = strecpy(base, thisline);
88124139Sjoerg
88224139Sjoerg    /* zero fill the rest of it */
88324139Sjoerg    memzero(p, display_width - (p - base));
88424139Sjoerg}
88524139Sjoerg
886301836Sngievoid
88724139Sjoergu_process(line, newline)
88824139Sjoerg
88924139Sjoergint line;
89024139Sjoergchar *newline;
89124139Sjoerg
89224139Sjoerg{
89324139Sjoerg    register char *optr;
89424139Sjoerg    register int screen_line = line + Header_lines;
89524139Sjoerg    register char *bufferline;
89624139Sjoerg
89724139Sjoerg    /* remember a pointer to the current line in the screen buffer */
89824139Sjoerg    bufferline = &screenbuf[lineindex(line)];
89924139Sjoerg
90024139Sjoerg    /* truncate the line to conform to our current screen width */
90124139Sjoerg    newline[display_width] = '\0';
90224139Sjoerg
90324139Sjoerg    /* is line higher than we went on the last display? */
90424139Sjoerg    if (line >= last_hi)
90524139Sjoerg    {
90624139Sjoerg	/* yes, just ignore screenbuf and write it out directly */
90724139Sjoerg	/* get positioned on the correct line */
90824139Sjoerg	if (screen_line - lastline == 1)
90924139Sjoerg	{
91024139Sjoerg	    putchar('\n');
91124139Sjoerg	    lastline++;
91224139Sjoerg	}
91324139Sjoerg	else
91424139Sjoerg	{
91524139Sjoerg	    Move_to(0, screen_line);
91624139Sjoerg	    lastline = screen_line;
91724139Sjoerg	}
91824139Sjoerg
91924139Sjoerg	/* now write the line */
92024139Sjoerg	fputs(newline, stdout);
92124139Sjoerg
92224139Sjoerg	/* copy it in to the buffer */
92324139Sjoerg	optr = strecpy(bufferline, newline);
92424139Sjoerg
92524139Sjoerg	/* zero fill the rest of it */
92624139Sjoerg	memzero(optr, display_width - (optr - bufferline));
92724139Sjoerg    }
92824139Sjoerg    else
92924139Sjoerg    {
93024139Sjoerg	line_update(bufferline, newline, 0, line + Header_lines);
93124139Sjoerg    }
93224139Sjoerg}
93324139Sjoerg
934301836Sngievoid
93524139Sjoergu_endscreen(hi)
93624139Sjoerg
937301836Sngieint hi;
93824139Sjoerg
93924139Sjoerg{
94024139Sjoerg    register int screen_line = hi + Header_lines;
94124139Sjoerg    register int i;
94224139Sjoerg
94324139Sjoerg    if (smart_terminal)
94424139Sjoerg    {
94524139Sjoerg	if (hi < last_hi)
94624139Sjoerg	{
94724139Sjoerg	    /* need to blank the remainder of the screen */
94824139Sjoerg	    /* but only if there is any screen left below this line */
94924139Sjoerg	    if (lastline + 1 < screen_length)
95024139Sjoerg	    {
95124139Sjoerg		/* efficiently move to the end of currently displayed info */
95224139Sjoerg		if (screen_line - lastline < 5)
95324139Sjoerg		{
95424139Sjoerg		    while (lastline < screen_line)
95524139Sjoerg		    {
95624139Sjoerg			putchar('\n');
95724139Sjoerg			lastline++;
95824139Sjoerg		    }
95924139Sjoerg		}
96024139Sjoerg		else
96124139Sjoerg		{
96224139Sjoerg		    Move_to(0, screen_line);
96324139Sjoerg		    lastline = screen_line;
96424139Sjoerg		}
96524139Sjoerg
96624139Sjoerg		if (clear_to_end)
96724139Sjoerg		{
96824139Sjoerg		    /* we can do this the easy way */
96924139Sjoerg		    putcap(clear_to_end);
97024139Sjoerg		}
97124139Sjoerg		else
97224139Sjoerg		{
97324139Sjoerg		    /* use clear_eol on each line */
97424139Sjoerg		    i = hi;
97524139Sjoerg		    while ((void) clear_eol(strlen(&screenbuf[lineindex(i++)])), i < last_hi)
97624139Sjoerg		    {
97724139Sjoerg			putchar('\n');
97824139Sjoerg		    }
97924139Sjoerg		}
98024139Sjoerg	    }
98124139Sjoerg	}
98224139Sjoerg	last_hi = hi;
98324139Sjoerg
98424139Sjoerg	/* move the cursor to a pleasant place */
98524139Sjoerg	Move_to(x_idlecursor, y_idlecursor);
98624139Sjoerg	lastline = y_idlecursor;
98724139Sjoerg    }
98824139Sjoerg    else
98924139Sjoerg    {
99024139Sjoerg	/* separate this display from the next with some vertical room */
99124139Sjoerg	fputs("\n\n", stdout);
99224139Sjoerg    }
99324139Sjoerg}
99424139Sjoerg
995301836Sngievoid
99624139Sjoergdisplay_header(t)
99724139Sjoerg
99824139Sjoergint t;
99924139Sjoerg
100024139Sjoerg{
100124139Sjoerg    if (t)
100224139Sjoerg    {
100324139Sjoerg	header_status = ON;
100424139Sjoerg    }
100524139Sjoerg    else if (header_status == ON)
100624139Sjoerg    {
100724139Sjoerg	header_status = ERASE;
100824139Sjoerg    }
100924139Sjoerg}
101024139Sjoerg
101124139Sjoerg/*VARARGS2*/
1012301836Sngievoid
101324139Sjoergnew_message(type, msgfmt, a1, a2, a3)
101424139Sjoerg
101524139Sjoergint type;
101624139Sjoergchar *msgfmt;
101724139Sjoergcaddr_t a1, a2, a3;
101824139Sjoerg
101924139Sjoerg{
102024139Sjoerg    register int i;
102124139Sjoerg
102224139Sjoerg    /* first, format the message */
102366641Simp    (void) snprintf(next_msg, sizeof(next_msg), msgfmt, a1, a2, a3);
102424139Sjoerg
102524139Sjoerg    if (msglen > 0)
102624139Sjoerg    {
102724139Sjoerg	/* message there already -- can we clear it? */
102824139Sjoerg	if (!overstrike)
102924139Sjoerg	{
103024139Sjoerg	    /* yes -- write it and clear to end */
103124139Sjoerg	    i = strlen(next_msg);
103224139Sjoerg	    if ((type & MT_delayed) == 0)
103324139Sjoerg	    {
103424139Sjoerg		type & MT_standout ? standout(next_msg) :
103524139Sjoerg		                     fputs(next_msg, stdout);
103624139Sjoerg		(void) clear_eol(msglen - i);
103724139Sjoerg		msglen = i;
103824139Sjoerg		next_msg[0] = '\0';
103924139Sjoerg	    }
104024139Sjoerg	}
104124139Sjoerg    }
104224139Sjoerg    else
104324139Sjoerg    {
104424139Sjoerg	if ((type & MT_delayed) == 0)
104524139Sjoerg	{
104624139Sjoerg	    type & MT_standout ? standout(next_msg) : fputs(next_msg, stdout);
104724139Sjoerg	    msglen = strlen(next_msg);
104824139Sjoerg	    next_msg[0] = '\0';
104924139Sjoerg	}
105024139Sjoerg    }
105124139Sjoerg}
105224139Sjoerg
1053301836Sngievoid
105424139Sjoergclear_message()
105524139Sjoerg
105624139Sjoerg{
105724139Sjoerg    if (clear_eol(msglen) == 1)
105824139Sjoerg    {
105924139Sjoerg	putchar('\r');
106024139Sjoerg    }
106124139Sjoerg}
106224139Sjoerg
1063301836Sngieint
106424139Sjoergreadline(buffer, size, numeric)
106524139Sjoerg
106624139Sjoergchar *buffer;
106724139Sjoergint  size;
106824139Sjoergint  numeric;
106924139Sjoerg
107024139Sjoerg{
107124139Sjoerg    register char *ptr = buffer;
107224139Sjoerg    register char ch;
107324139Sjoerg    register char cnt = 0;
107424139Sjoerg    register char maxcnt = 0;
107524139Sjoerg
107624139Sjoerg    /* allow room for null terminator */
107724139Sjoerg    size -= 1;
107824139Sjoerg
107924139Sjoerg    /* read loop */
108024139Sjoerg    while ((fflush(stdout), read(0, ptr, 1) > 0))
108124139Sjoerg    {
108224139Sjoerg	/* newline means we are done */
108324142Sjoerg	if ((ch = *ptr) == '\n' || ch == '\r')
108424139Sjoerg	{
108524139Sjoerg	    break;
108624139Sjoerg	}
108724139Sjoerg
108824139Sjoerg	/* handle special editing characters */
108924139Sjoerg	if (ch == ch_kill)
109024139Sjoerg	{
109124139Sjoerg	    /* kill line -- account for overstriking */
109224139Sjoerg	    if (overstrike)
109324139Sjoerg	    {
109424139Sjoerg		msglen += maxcnt;
109524139Sjoerg	    }
109624139Sjoerg
109724139Sjoerg	    /* return null string */
109824139Sjoerg	    *buffer = '\0';
109924139Sjoerg	    putchar('\r');
110024139Sjoerg	    return(-1);
110124139Sjoerg	}
110224139Sjoerg	else if (ch == ch_erase)
110324139Sjoerg	{
110424139Sjoerg	    /* erase previous character */
110524139Sjoerg	    if (cnt <= 0)
110624139Sjoerg	    {
110724139Sjoerg		/* none to erase! */
110824139Sjoerg		putchar('\7');
110924139Sjoerg	    }
111024139Sjoerg	    else
111124139Sjoerg	    {
111224139Sjoerg		fputs("\b \b", stdout);
111324139Sjoerg		ptr--;
111424139Sjoerg		cnt--;
111524139Sjoerg	    }
111624139Sjoerg	}
111724139Sjoerg	/* check for character validity and buffer overflow */
111824139Sjoerg	else if (cnt == size || (numeric && !isdigit(ch)) ||
111924139Sjoerg		!isprint(ch))
112024139Sjoerg	{
112124139Sjoerg	    /* not legal */
112224139Sjoerg	    putchar('\7');
112324139Sjoerg	}
112424139Sjoerg	else
112524139Sjoerg	{
112624139Sjoerg	    /* echo it and store it in the buffer */
112724139Sjoerg	    putchar(ch);
112824139Sjoerg	    ptr++;
112924139Sjoerg	    cnt++;
113024139Sjoerg	    if (cnt > maxcnt)
113124139Sjoerg	    {
113224139Sjoerg		maxcnt = cnt;
113324139Sjoerg	    }
113424139Sjoerg	}
113524139Sjoerg    }
113624139Sjoerg
113724139Sjoerg    /* all done -- null terminate the string */
113824139Sjoerg    *ptr = '\0';
113924139Sjoerg
114024139Sjoerg    /* account for the extra characters in the message area */
114124139Sjoerg    /* (if terminal overstrikes, remember the furthest they went) */
114224139Sjoerg    msglen += overstrike ? maxcnt : cnt;
114324139Sjoerg
114424139Sjoerg    /* return either inputted number or string length */
114524139Sjoerg    putchar('\r');
114624139Sjoerg    return(cnt == 0 ? -1 : numeric ? atoi(buffer) : cnt);
114724139Sjoerg}
114824139Sjoerg
114924139Sjoerg/* internal support routines */
115024139Sjoerg
115124139Sjoergstatic int string_count(pp)
115224139Sjoerg
115324139Sjoergregister char **pp;
115424139Sjoerg
115524139Sjoerg{
115624139Sjoerg    register int cnt;
115724139Sjoerg
115824139Sjoerg    cnt = 0;
115924139Sjoerg    while (*pp++ != NULL)
116024139Sjoerg    {
116124139Sjoerg	cnt++;
116224139Sjoerg    }
116324139Sjoerg    return(cnt);
116424139Sjoerg}
116524139Sjoerg
116624139Sjoergstatic void summary_format(str, numbers, names)
116724139Sjoerg
116824139Sjoergchar *str;
116924139Sjoergint *numbers;
117024139Sjoergregister char **names;
117124139Sjoerg
117224139Sjoerg{
117324139Sjoerg    register char *p;
117424139Sjoerg    register int num;
117524139Sjoerg    register char *thisname;
117624139Sjoerg    register int useM = No;
117724139Sjoerg
117824139Sjoerg    /* format each number followed by its string */
117924139Sjoerg    p = str;
118024139Sjoerg    while ((thisname = *names++) != NULL)
118124139Sjoerg    {
118224139Sjoerg	/* get the number to format */
118324139Sjoerg	num = *numbers++;
118424139Sjoerg
118524139Sjoerg	/* display only non-zero numbers */
118624139Sjoerg	if (num > 0)
118724139Sjoerg	{
118824139Sjoerg	    /* is this number in kilobytes? */
118924139Sjoerg	    if (thisname[0] == 'K')
119024139Sjoerg	    {
119124139Sjoerg		/* yes: format it as a memory value */
119224139Sjoerg		p = strecpy(p, format_k(num));
119324139Sjoerg
119424139Sjoerg		/* skip over the K, since it was included by format_k */
119524139Sjoerg		p = strecpy(p, thisname+1);
119624139Sjoerg	    }
119724139Sjoerg	    else
119824139Sjoerg	    {
119924139Sjoerg		p = strecpy(p, itoa(num));
120024139Sjoerg		p = strecpy(p, thisname);
120124139Sjoerg	    }
120224139Sjoerg	}
120324139Sjoerg
120424139Sjoerg	/* ignore negative numbers, but display corresponding string */
120524139Sjoerg	else if (num < 0)
120624139Sjoerg	{
120724139Sjoerg	    p = strecpy(p, thisname);
120824139Sjoerg	}
120924139Sjoerg    }
121024139Sjoerg
121124139Sjoerg    /* if the last two characters in the string are ", ", delete them */
121224139Sjoerg    p -= 2;
121324139Sjoerg    if (p >= str && p[0] == ',' && p[1] == ' ')
121424139Sjoerg    {
121524139Sjoerg	*p = '\0';
121624139Sjoerg    }
121724139Sjoerg}
121824139Sjoerg
121924139Sjoergstatic void line_update(old, new, start, line)
122024139Sjoerg
122124139Sjoergregister char *old;
122224139Sjoergregister char *new;
122324139Sjoergint start;
122424139Sjoergint line;
122524139Sjoerg
122624139Sjoerg{
122724139Sjoerg    register int ch;
122824139Sjoerg    register int diff;
122924139Sjoerg    register int newcol = start + 1;
123024139Sjoerg    register int lastcol = start;
123124139Sjoerg    char cursor_on_line = No;
123224139Sjoerg    char *current;
123324139Sjoerg
123424139Sjoerg    /* compare the two strings and only rewrite what has changed */
123524139Sjoerg    current = old;
123624139Sjoerg#ifdef DEBUG
123724139Sjoerg    fprintf(debug, "line_update, starting at %d\n", start);
123824139Sjoerg    fputs(old, debug);
123924139Sjoerg    fputc('\n', debug);
124024139Sjoerg    fputs(new, debug);
124124139Sjoerg    fputs("\n-\n", debug);
124224139Sjoerg#endif
124324139Sjoerg
124424139Sjoerg    /* start things off on the right foot		    */
124524139Sjoerg    /* this is to make sure the invariants get set up right */
124624139Sjoerg    if ((ch = *new++) != *old)
124724139Sjoerg    {
124824139Sjoerg	if (line - lastline == 1 && start == 0)
124924139Sjoerg	{
125024139Sjoerg	    putchar('\n');
125124139Sjoerg	}
125224139Sjoerg	else
125324139Sjoerg	{
125424139Sjoerg	    Move_to(start, line);
125524139Sjoerg	}
125624139Sjoerg	cursor_on_line = Yes;
125724139Sjoerg	putchar(ch);
125824139Sjoerg	*old = ch;
125924139Sjoerg	lastcol = 1;
126024139Sjoerg    }
126124139Sjoerg    old++;
126224139Sjoerg
126324139Sjoerg    /*
126424139Sjoerg     *  main loop -- check each character.  If the old and new aren't the
126524139Sjoerg     *	same, then update the display.  When the distance from the
126624139Sjoerg     *	current cursor position to the new change is small enough,
126724139Sjoerg     *	the characters that belong there are written to move the
126824139Sjoerg     *	cursor over.
126924139Sjoerg     *
127024139Sjoerg     *	Invariants:
127124139Sjoerg     *	    lastcol is the column where the cursor currently is sitting
127224139Sjoerg     *		(always one beyond the end of the last mismatch).
127324139Sjoerg     */
127424139Sjoerg    do		/* yes, a do...while */
127524139Sjoerg    {
127624139Sjoerg	if ((ch = *new++) != *old)
127724139Sjoerg	{
127824139Sjoerg	    /* new character is different from old	  */
127924139Sjoerg	    /* make sure the cursor is on top of this character */
128024139Sjoerg	    diff = newcol - lastcol;
128124139Sjoerg	    if (diff > 0)
128224139Sjoerg	    {
128324139Sjoerg		/* some motion is required--figure out which is shorter */
128424139Sjoerg		if (diff < 6 && cursor_on_line)
128524139Sjoerg		{
128624139Sjoerg		    /* overwrite old stuff--get it out of the old buffer */
128724139Sjoerg		    printf("%.*s", diff, &current[lastcol-start]);
128824139Sjoerg		}
128924139Sjoerg		else
129024139Sjoerg		{
129124139Sjoerg		    /* use cursor addressing */
129224139Sjoerg		    Move_to(newcol, line);
129324139Sjoerg		    cursor_on_line = Yes;
129424139Sjoerg		}
129524139Sjoerg		/* remember where the cursor is */
129624139Sjoerg		lastcol = newcol + 1;
129724139Sjoerg	    }
129824139Sjoerg	    else
129924139Sjoerg	    {
130024139Sjoerg		/* already there, update position */
130124139Sjoerg		lastcol++;
130224139Sjoerg	    }
130324139Sjoerg
130424139Sjoerg	    /* write what we need to */
130524139Sjoerg	    if (ch == '\0')
130624139Sjoerg	    {
130724139Sjoerg		/* at the end--terminate with a clear-to-end-of-line */
130824139Sjoerg		(void) clear_eol(strlen(old));
130924139Sjoerg	    }
131024139Sjoerg	    else
131124139Sjoerg	    {
131224139Sjoerg		/* write the new character */
131324139Sjoerg		putchar(ch);
131424139Sjoerg	    }
131524139Sjoerg	    /* put the new character in the screen buffer */
131624139Sjoerg	    *old = ch;
131724139Sjoerg	}
131824139Sjoerg
131924139Sjoerg	/* update working column and screen buffer pointer */
132024139Sjoerg	newcol++;
132124139Sjoerg	old++;
132224139Sjoerg
132324139Sjoerg    } while (ch != '\0');
132424139Sjoerg
132524139Sjoerg    /* zero out the rest of the line buffer -- MUST BE DONE! */
132624139Sjoerg    diff = display_width - newcol;
132724139Sjoerg    if (diff > 0)
132824139Sjoerg    {
132924139Sjoerg	memzero(old, diff);
133024139Sjoerg    }
133124139Sjoerg
133224139Sjoerg    /* remember where the current line is */
133324139Sjoerg    if (cursor_on_line)
133424139Sjoerg    {
133524139Sjoerg	lastline = line;
133624139Sjoerg    }
133724139Sjoerg}
133824139Sjoerg
133924139Sjoerg/*
134024139Sjoerg *  printable(str) - make the string pointed to by "str" into one that is
134124139Sjoerg *	printable (i.e.: all ascii), by converting all non-printable
134224139Sjoerg *	characters into '?'.  Replacements are done in place and a pointer
134324139Sjoerg *	to the original buffer is returned.
134424139Sjoerg */
134524139Sjoerg
134624139Sjoergchar *printable(str)
134724139Sjoerg
134824139Sjoergchar *str;
134924139Sjoerg
135024139Sjoerg{
135124139Sjoerg    register char *ptr;
135224139Sjoerg    register char ch;
135324139Sjoerg
135424139Sjoerg    ptr = str;
135524139Sjoerg    while ((ch = *ptr) != '\0')
135624139Sjoerg    {
135724139Sjoerg	if (!isprint(ch))
135824139Sjoerg	{
135924139Sjoerg	    *ptr = '?';
136024139Sjoerg	}
136124139Sjoerg	ptr++;
136224139Sjoerg    }
136324139Sjoerg    return(str);
136424139Sjoerg}
136542447Sobrien
1366301836Sngievoid
136742447Sobrieni_uptime(bt, tod)
136842447Sobrien
136942447Sobrienstruct timeval* bt;
137042447Sobrientime_t *tod;
137142447Sobrien
137242447Sobrien{
137342447Sobrien    time_t uptime;
137442447Sobrien    int days, hrs, mins, secs;
137542447Sobrien
137642447Sobrien    if (bt->tv_sec != -1) {
137742447Sobrien	uptime = *tod - bt->tv_sec;
137842447Sobrien	days = uptime / 86400;
137942447Sobrien	uptime %= 86400;
138042447Sobrien	hrs = uptime / 3600;
138142447Sobrien	uptime %= 3600;
138242447Sobrien	mins = uptime / 60;
138342447Sobrien	secs = uptime % 60;
138442447Sobrien
138542447Sobrien	/*
138642447Sobrien	 *  Display the uptime.
138742447Sobrien	 */
138842447Sobrien
138942447Sobrien	if (smart_terminal)
139042447Sobrien	{
139142447Sobrien	    Move_to((screen_width - 24) - (days > 9 ? 1 : 0), 0);
139242447Sobrien	}
139342447Sobrien	else
139442447Sobrien	{
139542447Sobrien	    fputs(" ", stdout);
139642447Sobrien	}
139742447Sobrien	printf(" up %d+%02d:%02d:%02d", days, hrs, mins, secs);
139842447Sobrien    }
139942447Sobrien}
1400