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"
3224139Sjoerg#include <ctype.h>
3324139Sjoerg#include <time.h>
3441943Sobrien#include <sys/time.h>
3524139Sjoerg
3624139Sjoerg#include "screen.h"		/* interface to screen package */
3724139Sjoerg#include "layout.h"		/* defines for screen position layout */
3824139Sjoerg#include "display.h"
3924139Sjoerg#include "top.h"
4024139Sjoerg#include "top.local.h"
4124139Sjoerg#include "boolean.h"
4224139Sjoerg#include "machine.h"		/* we should eliminate this!!! */
4324139Sjoerg#include "utils.h"
4424139Sjoerg
4524139Sjoerg#ifdef DEBUG
4624139SjoergFILE *debug;
4724139Sjoerg#endif
4824139Sjoerg
4924139Sjoerg/* imported from screen.c */
5024139Sjoergextern int overstrike;
5124139Sjoerg
5224139Sjoergstatic int lmpid = 0;
5324139Sjoergstatic int last_hi = 0;		/* used in u_process and u_endscreen */
5424139Sjoergstatic int lastline = 0;
5524139Sjoergstatic int display_width = MAX_COLS;
5624139Sjoerg
5724139Sjoerg#define lineindex(l) ((l)*display_width)
5824139Sjoerg
5924139Sjoergchar *printable();
6024139Sjoerg
6124139Sjoerg/* things initialized by display_init and used thruout */
6224139Sjoerg
6324139Sjoerg/* buffer of proc information lines for display updating */
6424139Sjoergchar *screenbuf = NULL;
6524139Sjoerg
6624139Sjoergstatic char **procstate_names;
6724139Sjoergstatic char **cpustate_names;
6824139Sjoergstatic char **memory_names;
69237656Sjhbstatic char **arc_names;
7024142Sjoergstatic char **swap_names;
7124139Sjoerg
7224139Sjoergstatic int num_procstates;
7324139Sjoergstatic int num_cpustates;
7424139Sjoergstatic int num_memory;
7524142Sjoergstatic int num_swap;
7624139Sjoerg
7724139Sjoergstatic int *lprocstates;
7824139Sjoergstatic int *lcpustates;
7924139Sjoergstatic int *lmemory;
8024142Sjoergstatic int *lswap;
8124139Sjoerg
82175420Speterstatic int num_cpus;
8324139Sjoergstatic int *cpustate_columns;
8424139Sjoergstatic int cpustate_total_length;
85175420Speterstatic int cpustates_column;
8624139Sjoerg
8724139Sjoergstatic enum { OFF, ON, ERASE } header_status = ON;
8824139Sjoerg
8924139Sjoergstatic int string_count();
9024139Sjoergstatic void summary_format();
9124139Sjoergstatic void line_update();
9224139Sjoerg
93175420Speterint  x_lastpid =	10;
94175420Speterint  y_lastpid =	0;
95175420Speterint  x_loadave =	33;
96175420Speterint  x_loadave_nompid =	15;
97175420Speterint  y_loadave =	0;
98175420Speterint  x_procstate =	0;
99175420Speterint  y_procstate =	1;
100175420Speterint  x_brkdn =		15;
101175420Speterint  y_brkdn =		1;
102175420Speterint  x_mem =		5;
103175420Speterint  y_mem =		3;
104237656Sjhbint  x_arc =		5;
105237656Sjhbint  y_arc =		4;
106175420Speterint  x_swap =		6;
107175420Speterint  y_swap =		4;
108175420Speterint  y_message =	5;
109175420Speterint  x_header =		0;
110175420Speterint  y_header =		6;
111175420Speterint  x_idlecursor =	0;
112175420Speterint  y_idlecursor =	5;
113175420Speterint  y_procs =		7;
114175420Speter
115175420Speterint  y_cpustates =	2;
116175420Speterint  Header_lines =	7;
117175420Speter
11824139Sjoergint display_resize()
11924139Sjoerg
12024139Sjoerg{
12124139Sjoerg    register int lines;
12224139Sjoerg
12324139Sjoerg    /* first, deallocate any previous buffer that may have been there */
12424139Sjoerg    if (screenbuf != NULL)
12524139Sjoerg    {
12624139Sjoerg	free(screenbuf);
12724139Sjoerg    }
12824139Sjoerg
12924139Sjoerg    /* calculate the current dimensions */
13024139Sjoerg    /* if operating in "dumb" mode, we only need one line */
13124139Sjoerg    lines = smart_terminal ? screen_length - Header_lines : 1;
13224139Sjoerg
133101692Sdwmalone    if (lines < 0)
134101692Sdwmalone	lines = 0;
13524139Sjoerg    /* we don't want more than MAX_COLS columns, since the machine-dependent
13624139Sjoerg       modules make static allocations based on MAX_COLS and we don't want
13724139Sjoerg       to run off the end of their buffers */
13824139Sjoerg    display_width = screen_width;
13924139Sjoerg    if (display_width >= MAX_COLS)
14024139Sjoerg    {
14124139Sjoerg	display_width = MAX_COLS - 1;
14224139Sjoerg    }
14324139Sjoerg
14424139Sjoerg    /* now, allocate space for the screen buffer */
14524139Sjoerg    screenbuf = (char *)malloc(lines * display_width);
14624139Sjoerg    if (screenbuf == (char *)NULL)
14724139Sjoerg    {
14824139Sjoerg	/* oops! */
14924139Sjoerg	return(-1);
15024139Sjoerg    }
15124139Sjoerg
15224139Sjoerg    /* return number of lines available */
15324139Sjoerg    /* for dumb terminals, pretend like we can show any amount */
15424139Sjoerg    return(smart_terminal ? lines : Largest);
15524139Sjoerg}
15624139Sjoerg
157223936Sjhbint display_updatecpus(statics)
15824139Sjoerg
15924139Sjoergstruct statics *statics;
16024139Sjoerg
16124139Sjoerg{
162224205Sjhb    register int *lp;
16324139Sjoerg    register int lines;
16424139Sjoerg    register int i;
165223936Sjhb
16624139Sjoerg    /* call resize to do the dirty work */
16724139Sjoerg    lines = display_resize();
168224205Sjhb    if (pcpu_stats)
169224205Sjhb	num_cpus = statics->ncpus;
170224205Sjhb    else
171224205Sjhb	num_cpus = 1;
172175420Speter    cpustates_column = 5;	/* CPU: */
173175420Speter    if (num_cpus != 1)
174175420Speter    cpustates_column += 2;	/* CPU 0: */
175175420Speter    for (i = num_cpus; i > 9; i /= 10)
176175420Speter	cpustates_column++;
17724139Sjoerg
178224205Sjhb    /* fill the "last" array with all -1s, to insure correct updating */
179224205Sjhb    lp = lcpustates;
180224205Sjhb    i = num_cpustates * num_cpus;
181224205Sjhb    while (--i >= 0)
182224205Sjhb    {
183224205Sjhb	*lp++ = -1;
184224205Sjhb    }
185224205Sjhb
186223936Sjhb    return(lines);
187223936Sjhb}
188223936Sjhb
189223936Sjhbint display_init(statics)
190223936Sjhb
191223936Sjhbstruct statics *statics;
192223936Sjhb
193223936Sjhb{
194223936Sjhb    register int lines;
195223936Sjhb    register char **pp;
196223936Sjhb    register int *ip;
197223936Sjhb    register int i;
198223936Sjhb
199223936Sjhb    lines = display_updatecpus(statics);
200223936Sjhb
20124139Sjoerg    /* only do the rest if we need to */
20224139Sjoerg    if (lines > -1)
20324139Sjoerg    {
20424139Sjoerg	/* save pointers and allocate space for names */
20524139Sjoerg	procstate_names = statics->procstate_names;
20624139Sjoerg	num_procstates = string_count(procstate_names);
20724139Sjoerg	lprocstates = (int *)malloc(num_procstates * sizeof(int));
20824139Sjoerg
20924139Sjoerg	cpustate_names = statics->cpustate_names;
21024142Sjoerg
21124142Sjoerg	swap_names = statics->swap_names;
21224142Sjoerg	num_swap = string_count(swap_names);
21324142Sjoerg	lswap = (int *)malloc(num_swap * sizeof(int));
21424139Sjoerg	num_cpustates = string_count(cpustate_names);
215224205Sjhb	lcpustates = (int *)malloc(num_cpustates * sizeof(int) * statics->ncpus);
21624139Sjoerg	cpustate_columns = (int *)malloc(num_cpustates * sizeof(int));
21724139Sjoerg
21824139Sjoerg	memory_names = statics->memory_names;
21924139Sjoerg	num_memory = string_count(memory_names);
22024139Sjoerg	lmemory = (int *)malloc(num_memory * sizeof(int));
22124139Sjoerg
222237656Sjhb	arc_names = statics->arc_names;
223237656Sjhb
22424139Sjoerg	/* calculate starting columns where needed */
22524139Sjoerg	cpustate_total_length = 0;
22624139Sjoerg	pp = cpustate_names;
22724139Sjoerg	ip = cpustate_columns;
22824139Sjoerg	while (*pp != NULL)
22924139Sjoerg	{
23089758Sdwmalone	    *ip++ = cpustate_total_length;
23124139Sjoerg	    if ((i = strlen(*pp++)) > 0)
23224139Sjoerg	    {
23324139Sjoerg		cpustate_total_length += i + 8;
23424139Sjoerg	    }
23524139Sjoerg	}
23624139Sjoerg    }
23724139Sjoerg
23824139Sjoerg    /* return number of lines available */
23924139Sjoerg    return(lines);
24024139Sjoerg}
24124139Sjoerg
24224139Sjoergi_loadave(mpid, avenrun)
24324139Sjoerg
24424139Sjoergint mpid;
24524139Sjoergdouble *avenrun;
24624139Sjoerg
24724139Sjoerg{
24824139Sjoerg    register int i;
24924139Sjoerg
25024139Sjoerg    /* i_loadave also clears the screen, since it is first */
25124139Sjoerg    clear();
25224139Sjoerg
25324139Sjoerg    /* mpid == -1 implies this system doesn't have an _mpid */
25424139Sjoerg    if (mpid != -1)
25524139Sjoerg    {
25624139Sjoerg	printf("last pid: %5d;  ", mpid);
25724139Sjoerg    }
25824139Sjoerg
25924139Sjoerg    printf("load averages");
26024139Sjoerg
26124139Sjoerg    for (i = 0; i < 3; i++)
26224139Sjoerg    {
26324139Sjoerg	printf("%c %5.2f",
26424139Sjoerg	    i == 0 ? ':' : ',',
26524139Sjoerg	    avenrun[i]);
26624139Sjoerg    }
26724139Sjoerg    lmpid = mpid;
26824139Sjoerg}
26924139Sjoerg
27024139Sjoergu_loadave(mpid, avenrun)
27124139Sjoerg
27224139Sjoergint mpid;
27324139Sjoergdouble *avenrun;
27424139Sjoerg
27524139Sjoerg{
27624139Sjoerg    register int i;
27724139Sjoerg
27824139Sjoerg    if (mpid != -1)
27924139Sjoerg    {
28024139Sjoerg	/* change screen only when value has really changed */
28124139Sjoerg	if (mpid != lmpid)
28224139Sjoerg	{
28324139Sjoerg	    Move_to(x_lastpid, y_lastpid);
28424139Sjoerg	    printf("%5d", mpid);
28524139Sjoerg	    lmpid = mpid;
28624139Sjoerg	}
28724139Sjoerg
28824139Sjoerg	/* i remembers x coordinate to move to */
28924139Sjoerg	i = x_loadave;
29024139Sjoerg    }
29124139Sjoerg    else
29224139Sjoerg    {
29324139Sjoerg	i = x_loadave_nompid;
29424139Sjoerg    }
29524139Sjoerg
29624139Sjoerg    /* move into position for load averages */
29724139Sjoerg    Move_to(i, y_loadave);
29824139Sjoerg
29924139Sjoerg    /* display new load averages */
30024139Sjoerg    /* we should optimize this and only display changes */
30124139Sjoerg    for (i = 0; i < 3; i++)
30224139Sjoerg    {
30324139Sjoerg	printf("%s%5.2f",
30424139Sjoerg	    i == 0 ? "" : ", ",
30524139Sjoerg	    avenrun[i]);
30624139Sjoerg    }
30724139Sjoerg}
30824139Sjoerg
30924139Sjoergi_timeofday(tod)
31024139Sjoerg
31124139Sjoergtime_t *tod;
31224139Sjoerg
31324139Sjoerg{
31424139Sjoerg    /*
31524139Sjoerg     *  Display the current time.
31624139Sjoerg     *  "ctime" always returns a string that looks like this:
31724139Sjoerg     *
31824139Sjoerg     *	Sun Sep 16 01:03:52 1973
31924139Sjoerg     *      012345678901234567890123
32024139Sjoerg     *	          1         2
32124139Sjoerg     *
32224139Sjoerg     *  We want indices 11 thru 18 (length 8).
32324139Sjoerg     */
32424139Sjoerg
32524139Sjoerg    if (smart_terminal)
32624139Sjoerg    {
32724139Sjoerg	Move_to(screen_width - 8, 0);
32824139Sjoerg    }
32924139Sjoerg    else
33024139Sjoerg    {
33124139Sjoerg	fputs("    ", stdout);
33224139Sjoerg    }
33324139Sjoerg#ifdef DEBUG
33424139Sjoerg    {
33524139Sjoerg	char *foo;
33624139Sjoerg	foo = ctime(tod);
33724139Sjoerg	fputs(foo, stdout);
33824139Sjoerg    }
33924139Sjoerg#endif
34024139Sjoerg    printf("%-8.8s\n", &(ctime(tod)[11]));
34124139Sjoerg    lastline = 1;
34224139Sjoerg}
34324139Sjoerg
34424139Sjoergstatic int ltotal = 0;
34589758Sdwmalonestatic char procstates_buffer[MAX_COLS];
34624139Sjoerg
34724139Sjoerg/*
34824139Sjoerg *  *_procstates(total, brkdn, names) - print the process summary line
34924139Sjoerg *
35024139Sjoerg *  Assumptions:  cursor is at the beginning of the line on entry
35124139Sjoerg *		  lastline is valid
35224139Sjoerg */
35324139Sjoerg
35424139Sjoergi_procstates(total, brkdn)
35524139Sjoerg
35624139Sjoergint total;
35724139Sjoergint *brkdn;
35824139Sjoerg
35924139Sjoerg{
36024139Sjoerg    register int i;
36124139Sjoerg
36224139Sjoerg    /* write current number of processes and remember the value */
36324139Sjoerg    printf("%d processes:", total);
36424139Sjoerg    ltotal = total;
36524139Sjoerg
36624139Sjoerg    /* put out enough spaces to get to column 15 */
36724139Sjoerg    i = digits(total);
36824139Sjoerg    while (i++ < 4)
36924139Sjoerg    {
37024139Sjoerg	putchar(' ');
37124139Sjoerg    }
37224139Sjoerg
37324139Sjoerg    /* format and print the process state summary */
37424139Sjoerg    summary_format(procstates_buffer, brkdn, procstate_names);
37524139Sjoerg    fputs(procstates_buffer, stdout);
37624139Sjoerg
37724139Sjoerg    /* save the numbers for next time */
37824139Sjoerg    memcpy(lprocstates, brkdn, num_procstates * sizeof(int));
37924139Sjoerg}
38024139Sjoerg
38124139Sjoergu_procstates(total, brkdn)
38224139Sjoerg
38324139Sjoergint total;
38424139Sjoergint *brkdn;
38524139Sjoerg
38624139Sjoerg{
38789758Sdwmalone    static char new[MAX_COLS];
38824139Sjoerg    register int i;
38924139Sjoerg
39024139Sjoerg    /* update number of processes only if it has changed */
39124139Sjoerg    if (ltotal != total)
39224139Sjoerg    {
39324139Sjoerg	/* move and overwrite */
39424139Sjoerg#if (x_procstate == 0)
39524139Sjoerg	Move_to(x_procstate, y_procstate);
39624139Sjoerg#else
39724139Sjoerg	/* cursor is already there...no motion needed */
39824139Sjoerg	/* assert(lastline == 1); */
39924139Sjoerg#endif
40024139Sjoerg	printf("%d", total);
40124139Sjoerg
40224139Sjoerg	/* if number of digits differs, rewrite the label */
40324139Sjoerg	if (digits(total) != digits(ltotal))
40424139Sjoerg	{
40524139Sjoerg	    fputs(" processes:", stdout);
40624139Sjoerg	    /* put out enough spaces to get to column 15 */
40724139Sjoerg	    i = digits(total);
40824139Sjoerg	    while (i++ < 4)
40924139Sjoerg	    {
41024139Sjoerg		putchar(' ');
41124139Sjoerg	    }
41224139Sjoerg	    /* cursor may end up right where we want it!!! */
41324139Sjoerg	}
41424139Sjoerg
41524139Sjoerg	/* save new total */
41624139Sjoerg	ltotal = total;
41724139Sjoerg    }
41824139Sjoerg
41924139Sjoerg    /* see if any of the state numbers has changed */
42024139Sjoerg    if (memcmp(lprocstates, brkdn, num_procstates * sizeof(int)) != 0)
42124139Sjoerg    {
42224139Sjoerg	/* format and update the line */
42324139Sjoerg	summary_format(new, brkdn, procstate_names);
42424139Sjoerg	line_update(procstates_buffer, new, x_brkdn, y_brkdn);
42524139Sjoerg	memcpy(lprocstates, brkdn, num_procstates * sizeof(int));
42624139Sjoerg    }
42724139Sjoerg}
42824139Sjoerg
429175420Speter#ifdef no_more
43024139Sjoerg/*
43124139Sjoerg *  *_cpustates(states, names) - print the cpu state percentages
43224139Sjoerg *
43324139Sjoerg *  Assumptions:  cursor is on the PREVIOUS line
43424139Sjoerg */
43524139Sjoerg
43624139Sjoerg/* cpustates_tag() calculates the correct tag to use to label the line */
43724139Sjoerg
43824139Sjoergchar *cpustates_tag()
43924139Sjoerg
44024139Sjoerg{
44124139Sjoerg    register char *use;
44224139Sjoerg
44324139Sjoerg    static char *short_tag = "CPU: ";
44424139Sjoerg    static char *long_tag = "CPU states: ";
44524139Sjoerg
44624139Sjoerg    /* if length + strlen(long_tag) >= screen_width, then we have to
44724139Sjoerg       use the shorter tag (we subtract 2 to account for ": ") */
44824139Sjoerg    if (cpustate_total_length + (int)strlen(long_tag) - 2 >= screen_width)
44924139Sjoerg    {
45024139Sjoerg	use = short_tag;
45124139Sjoerg    }
45224139Sjoerg    else
45324139Sjoerg    {
45424139Sjoerg	use = long_tag;
45524139Sjoerg    }
45624139Sjoerg
45724139Sjoerg    /* set cpustates_column accordingly then return result */
45824139Sjoerg    cpustates_column = strlen(use);
45924139Sjoerg    return(use);
46024139Sjoerg}
461175420Speter#endif
46224139Sjoerg
46324139Sjoergi_cpustates(states)
46424139Sjoerg
46524139Sjoergregister int *states;
46624139Sjoerg
46724139Sjoerg{
46824139Sjoerg    register int i = 0;
46924139Sjoerg    register int value;
470175420Speter    register char **names;
47124139Sjoerg    register char *thisname;
472175420Speter    int cpu;
47324139Sjoerg
474175420Speterfor (cpu = 0; cpu < num_cpus; cpu++) {
475175420Speter    names = cpustate_names;
476175420Speter
47724139Sjoerg    /* print tag and bump lastline */
478175420Speter    if (num_cpus == 1)
479175420Speter	printf("\nCPU: ");
480218171Sjhb    else {
481218171Sjhb	value = printf("\nCPU %d: ", cpu);
482218171Sjhb	while (value++ <= cpustates_column)
483218171Sjhb		printf(" ");
484218171Sjhb    }
48524139Sjoerg    lastline++;
48624139Sjoerg
48724139Sjoerg    /* now walk thru the names and print the line */
48824139Sjoerg    while ((thisname = *names++) != NULL)
48924139Sjoerg    {
49024139Sjoerg	if (*thisname != '\0')
49124139Sjoerg	{
49224139Sjoerg	    /* retrieve the value and remember it */
49324139Sjoerg	    value = *states++;
49424139Sjoerg
49524139Sjoerg	    /* if percentage is >= 1000, print it as 100% */
49624139Sjoerg	    printf((value >= 1000 ? "%s%4.0f%% %s" : "%s%4.1f%% %s"),
497175420Speter		   (i++ % num_cpustates) == 0 ? "" : ", ",
49824139Sjoerg		   ((float)value)/10.,
49924139Sjoerg		   thisname);
50024139Sjoerg	}
50124139Sjoerg    }
502175420Speter}
50324139Sjoerg
50424139Sjoerg    /* copy over values into "last" array */
505175420Speter    memcpy(lcpustates, states, num_cpustates * sizeof(int) * num_cpus);
50624139Sjoerg}
50724139Sjoerg
50824139Sjoergu_cpustates(states)
50924139Sjoerg
51024139Sjoergregister int *states;
51124139Sjoerg
51224139Sjoerg{
51324139Sjoerg    register int value;
514175420Speter    register char **names;
51524139Sjoerg    register char *thisname;
51624139Sjoerg    register int *lp;
51724139Sjoerg    register int *colp;
518175420Speter    int cpu;
51924139Sjoerg
520175420Speterfor (cpu = 0; cpu < num_cpus; cpu++) {
521175420Speter    names = cpustate_names;
522175420Speter
523175420Speter    Move_to(cpustates_column, y_cpustates + cpu);
524175420Speter    lastline = y_cpustates + cpu;
525175420Speter    lp = lcpustates + (cpu * num_cpustates);
52624139Sjoerg    colp = cpustate_columns;
52724139Sjoerg
52824139Sjoerg    /* we could be much more optimal about this */
52924139Sjoerg    while ((thisname = *names++) != NULL)
53024139Sjoerg    {
53124139Sjoerg	if (*thisname != '\0')
53224139Sjoerg	{
53324139Sjoerg	    /* did the value change since last time? */
53424139Sjoerg	    if (*lp != *states)
53524139Sjoerg	    {
53624139Sjoerg		/* yes, move and change */
537175420Speter		Move_to(cpustates_column + *colp, y_cpustates + cpu);
538175420Speter		lastline = y_cpustates + cpu;
53924139Sjoerg
54024139Sjoerg		/* retrieve value and remember it */
54124139Sjoerg		value = *states;
54224139Sjoerg
54324139Sjoerg		/* if percentage is >= 1000, print it as 100% */
54424139Sjoerg		printf((value >= 1000 ? "%4.0f" : "%4.1f"),
54524139Sjoerg		       ((double)value)/10.);
54624139Sjoerg
54724139Sjoerg		/* remember it for next time */
54889758Sdwmalone		*lp = value;
54924139Sjoerg	    }
55024139Sjoerg	}
55124139Sjoerg
55224139Sjoerg	/* increment and move on */
55324139Sjoerg	lp++;
55424139Sjoerg	states++;
55524139Sjoerg	colp++;
55624139Sjoerg    }
55724139Sjoerg}
558175420Speter}
55924139Sjoerg
56024139Sjoergz_cpustates()
56124139Sjoerg
56224139Sjoerg{
56324139Sjoerg    register int i = 0;
564175420Speter    register char **names;
56524139Sjoerg    register char *thisname;
56624139Sjoerg    register int *lp;
567218171Sjhb    int cpu, value;
56824139Sjoerg
569175420Speterfor (cpu = 0; cpu < num_cpus; cpu++) {
570175420Speter    names = cpustate_names;
571175420Speter
57224139Sjoerg    /* show tag and bump lastline */
573175420Speter    if (num_cpus == 1)
574175420Speter	printf("\nCPU: ");
575218171Sjhb    else {
576218171Sjhb	value = printf("\nCPU %d: ", cpu);
577218171Sjhb	while (value++ <= cpustates_column)
578218171Sjhb		printf(" ");
579218171Sjhb    }
58024139Sjoerg    lastline++;
58124139Sjoerg
58224139Sjoerg    while ((thisname = *names++) != NULL)
58324139Sjoerg    {
58424139Sjoerg	if (*thisname != '\0')
58524139Sjoerg	{
586175420Speter	    printf("%s    %% %s", (i++ % num_cpustates) == 0 ? "" : ", ", thisname);
58724139Sjoerg	}
58824139Sjoerg    }
589175420Speter}
59024139Sjoerg
59124139Sjoerg    /* fill the "last" array with all -1s, to insure correct updating */
59224139Sjoerg    lp = lcpustates;
593175420Speter    i = num_cpustates * num_cpus;
59424139Sjoerg    while (--i >= 0)
59524139Sjoerg    {
59624139Sjoerg	*lp++ = -1;
59724139Sjoerg    }
59824139Sjoerg}
59924139Sjoerg
60024139Sjoerg/*
60124139Sjoerg *  *_memory(stats) - print "Memory: " followed by the memory summary string
60224139Sjoerg *
60324139Sjoerg *  Assumptions:  cursor is on "lastline"
60424139Sjoerg *                for i_memory ONLY: cursor is on the previous line
60524139Sjoerg */
60624139Sjoerg
60724139Sjoergchar memory_buffer[MAX_COLS];
60824139Sjoerg
60924139Sjoergi_memory(stats)
61024139Sjoerg
61124139Sjoergint *stats;
61224139Sjoerg
61324139Sjoerg{
61424142Sjoerg    fputs("\nMem: ", stdout);
61524139Sjoerg    lastline++;
61624139Sjoerg
61724139Sjoerg    /* format and print the memory summary */
61824139Sjoerg    summary_format(memory_buffer, stats, memory_names);
61924139Sjoerg    fputs(memory_buffer, stdout);
62024139Sjoerg}
62124139Sjoerg
62224139Sjoergu_memory(stats)
62324139Sjoerg
62424139Sjoergint *stats;
62524139Sjoerg
62624139Sjoerg{
62724139Sjoerg    static char new[MAX_COLS];
62824139Sjoerg
62924139Sjoerg    /* format the new line */
63024139Sjoerg    summary_format(new, stats, memory_names);
63124139Sjoerg    line_update(memory_buffer, new, x_mem, y_mem);
63224139Sjoerg}
63324139Sjoerg
63424139Sjoerg/*
635237656Sjhb *  *_arc(stats) - print "ARC: " followed by the ARC summary string
636237656Sjhb *
637237656Sjhb *  Assumptions:  cursor is on "lastline"
638237656Sjhb *                for i_arc ONLY: cursor is on the previous line
639237656Sjhb */
640237656Sjhbchar arc_buffer[MAX_COLS];
641237656Sjhb
642237656Sjhbi_arc(stats)
643237656Sjhb
644237656Sjhbint *stats;
645237656Sjhb
646237656Sjhb{
647237656Sjhb    if (arc_names == NULL)
648237656Sjhb	return (0);
649237656Sjhb
650237656Sjhb    fputs("\nARC: ", stdout);
651237656Sjhb    lastline++;
652237656Sjhb
653237656Sjhb    /* format and print the memory summary */
654237656Sjhb    summary_format(arc_buffer, stats, arc_names);
655237656Sjhb    fputs(arc_buffer, stdout);
656237656Sjhb}
657237656Sjhb
658237656Sjhbu_arc(stats)
659237656Sjhb
660237656Sjhbint *stats;
661237656Sjhb
662237656Sjhb{
663237656Sjhb    static char new[MAX_COLS];
664237656Sjhb
665237656Sjhb    if (arc_names == NULL)
666237656Sjhb	return (0);
667237656Sjhb
668237656Sjhb    /* format the new line */
669237656Sjhb    summary_format(new, stats, arc_names);
670237656Sjhb    line_update(arc_buffer, new, x_arc, y_arc);
671237656Sjhb}
672237656Sjhb
673237656Sjhb
674237656Sjhb/*
67524142Sjoerg *  *_swap(stats) - print "Swap: " followed by the swap summary string
67624142Sjoerg *
67724142Sjoerg *  Assumptions:  cursor is on "lastline"
67824142Sjoerg *                for i_swap ONLY: cursor is on the previous line
67924142Sjoerg */
68024142Sjoerg
68124142Sjoergchar swap_buffer[MAX_COLS];
68224142Sjoerg
68324142Sjoergi_swap(stats)
68424142Sjoerg
68524142Sjoergint *stats;
68624142Sjoerg
68724142Sjoerg{
68824142Sjoerg    fputs("\nSwap: ", stdout);
68924142Sjoerg    lastline++;
69024142Sjoerg
69124142Sjoerg    /* format and print the swap summary */
69224142Sjoerg    summary_format(swap_buffer, stats, swap_names);
69324142Sjoerg    fputs(swap_buffer, stdout);
69424142Sjoerg}
69524142Sjoerg
69624142Sjoergu_swap(stats)
69724142Sjoerg
69824142Sjoergint *stats;
69924142Sjoerg
70024142Sjoerg{
70124142Sjoerg    static char new[MAX_COLS];
70224142Sjoerg
70324142Sjoerg    /* format the new line */
70424142Sjoerg    summary_format(new, stats, swap_names);
70524142Sjoerg    line_update(swap_buffer, new, x_swap, y_swap);
70624142Sjoerg}
70724142Sjoerg
70824142Sjoerg/*
70924139Sjoerg *  *_message() - print the next pending message line, or erase the one
71024139Sjoerg *                that is there.
71124139Sjoerg *
71224139Sjoerg *  Note that u_message is (currently) the same as i_message.
71324139Sjoerg *
71424139Sjoerg *  Assumptions:  lastline is consistent
71524139Sjoerg */
71624139Sjoerg
71724139Sjoerg/*
71824139Sjoerg *  i_message is funny because it gets its message asynchronously (with
71924139Sjoerg *	respect to screen updates).
72024139Sjoerg */
72124139Sjoerg
72224139Sjoergstatic char next_msg[MAX_COLS + 5];
72324139Sjoergstatic int msglen = 0;
72424139Sjoerg/* Invariant: msglen is always the length of the message currently displayed
72524139Sjoerg   on the screen (even when next_msg doesn't contain that message). */
72624139Sjoerg
72724139Sjoergi_message()
72824139Sjoerg
72924139Sjoerg{
73024139Sjoerg    while (lastline < y_message)
73124139Sjoerg    {
73224139Sjoerg	fputc('\n', stdout);
73324139Sjoerg	lastline++;
73424139Sjoerg    }
73524139Sjoerg    if (next_msg[0] != '\0')
73624139Sjoerg    {
73724139Sjoerg	standout(next_msg);
73824139Sjoerg	msglen = strlen(next_msg);
73924139Sjoerg	next_msg[0] = '\0';
74024139Sjoerg    }
74124139Sjoerg    else if (msglen > 0)
74224139Sjoerg    {
74324139Sjoerg	(void) clear_eol(msglen);
74424139Sjoerg	msglen = 0;
74524139Sjoerg    }
74624139Sjoerg}
74724139Sjoerg
74824139Sjoergu_message()
74924139Sjoerg
75024139Sjoerg{
75124139Sjoerg    i_message();
75224139Sjoerg}
75324139Sjoerg
75424139Sjoergstatic int header_length;
75524139Sjoerg
75624139Sjoerg/*
757146344Skeramida * Trim a header string to the current display width and return a newly
758146344Skeramida * allocated area with the trimmed header.
759146344Skeramida */
760146344Skeramida
761146344Skeramidachar *
762146344Skeramidatrim_header(text)
763146344Skeramida
764146344Skeramidachar *text;
765146344Skeramida
766146344Skeramida{
767146344Skeramida	char *s;
768146344Skeramida	int width;
769146344Skeramida
770146344Skeramida	s = NULL;
771223342Sdelphij	width = display_width;
772146344Skeramida	header_length = strlen(text);
773146344Skeramida	if (header_length >= width) {
774146344Skeramida		s = malloc((width + 1) * sizeof(char));
775146344Skeramida		if (s == NULL)
776146344Skeramida			return (NULL);
777146344Skeramida		strncpy(s, text, width);
778146344Skeramida		s[width] = '\0';
779146344Skeramida	}
780146344Skeramida	return (s);
781146344Skeramida}
782146344Skeramida
783146344Skeramida/*
78424139Sjoerg *  *_header(text) - print the header for the process area
78524139Sjoerg *
78624139Sjoerg *  Assumptions:  cursor is on the previous line and lastline is consistent
78724139Sjoerg */
78824139Sjoerg
78924139Sjoergi_header(text)
79024139Sjoerg
79124139Sjoergchar *text;
79224139Sjoerg
79324139Sjoerg{
794146344Skeramida    char *s;
795146344Skeramida
796146344Skeramida    s = trim_header(text);
797146344Skeramida    if (s != NULL)
798146344Skeramida	text = s;
799146344Skeramida
80024139Sjoerg    if (header_status == ON)
80124139Sjoerg    {
80224139Sjoerg	putchar('\n');
803223342Sdelphij	fputs(text, stdout);
80424139Sjoerg	lastline++;
80524139Sjoerg    }
80624139Sjoerg    else if (header_status == ERASE)
80724139Sjoerg    {
80824139Sjoerg	header_status = OFF;
80924139Sjoerg    }
810146344Skeramida    free(s);
81124139Sjoerg}
81224139Sjoerg
81324139Sjoerg/*ARGSUSED*/
81424139Sjoergu_header(text)
81524139Sjoerg
81624139Sjoergchar *text;		/* ignored */
81724139Sjoerg
81824139Sjoerg{
819146344Skeramida
82024139Sjoerg    if (header_status == ERASE)
82124139Sjoerg    {
82224139Sjoerg	putchar('\n');
82324139Sjoerg	lastline++;
82424139Sjoerg	clear_eol(header_length);
82524139Sjoerg	header_status = OFF;
82624139Sjoerg    }
82724139Sjoerg}
82824139Sjoerg
82924139Sjoerg/*
83024139Sjoerg *  *_process(line, thisline) - print one process line
83124139Sjoerg *
83224139Sjoerg *  Assumptions:  lastline is consistent
83324139Sjoerg */
83424139Sjoerg
83524139Sjoergi_process(line, thisline)
83624139Sjoerg
83724139Sjoergint line;
83824139Sjoergchar *thisline;
83924139Sjoerg
84024139Sjoerg{
84124139Sjoerg    register char *p;
84224139Sjoerg    register char *base;
84324139Sjoerg
84424139Sjoerg    /* make sure we are on the correct line */
84524139Sjoerg    while (lastline < y_procs + line)
84624139Sjoerg    {
84724139Sjoerg	putchar('\n');
84824139Sjoerg	lastline++;
84924139Sjoerg    }
85024139Sjoerg
85124139Sjoerg    /* truncate the line to conform to our current screen width */
85224139Sjoerg    thisline[display_width] = '\0';
85324139Sjoerg
85424139Sjoerg    /* write the line out */
85524139Sjoerg    fputs(thisline, stdout);
85624139Sjoerg
85724139Sjoerg    /* copy it in to our buffer */
85824139Sjoerg    base = smart_terminal ? screenbuf + lineindex(line) : screenbuf;
85924139Sjoerg    p = strecpy(base, thisline);
86024139Sjoerg
86124139Sjoerg    /* zero fill the rest of it */
86224139Sjoerg    memzero(p, display_width - (p - base));
86324139Sjoerg}
86424139Sjoerg
86524139Sjoergu_process(line, newline)
86624139Sjoerg
86724139Sjoergint line;
86824139Sjoergchar *newline;
86924139Sjoerg
87024139Sjoerg{
87124139Sjoerg    register char *optr;
87224139Sjoerg    register int screen_line = line + Header_lines;
87324139Sjoerg    register char *bufferline;
87424139Sjoerg
87524139Sjoerg    /* remember a pointer to the current line in the screen buffer */
87624139Sjoerg    bufferline = &screenbuf[lineindex(line)];
87724139Sjoerg
87824139Sjoerg    /* truncate the line to conform to our current screen width */
87924139Sjoerg    newline[display_width] = '\0';
88024139Sjoerg
88124139Sjoerg    /* is line higher than we went on the last display? */
88224139Sjoerg    if (line >= last_hi)
88324139Sjoerg    {
88424139Sjoerg	/* yes, just ignore screenbuf and write it out directly */
88524139Sjoerg	/* get positioned on the correct line */
88624139Sjoerg	if (screen_line - lastline == 1)
88724139Sjoerg	{
88824139Sjoerg	    putchar('\n');
88924139Sjoerg	    lastline++;
89024139Sjoerg	}
89124139Sjoerg	else
89224139Sjoerg	{
89324139Sjoerg	    Move_to(0, screen_line);
89424139Sjoerg	    lastline = screen_line;
89524139Sjoerg	}
89624139Sjoerg
89724139Sjoerg	/* now write the line */
89824139Sjoerg	fputs(newline, stdout);
89924139Sjoerg
90024139Sjoerg	/* copy it in to the buffer */
90124139Sjoerg	optr = strecpy(bufferline, newline);
90224139Sjoerg
90324139Sjoerg	/* zero fill the rest of it */
90424139Sjoerg	memzero(optr, display_width - (optr - bufferline));
90524139Sjoerg    }
90624139Sjoerg    else
90724139Sjoerg    {
90824139Sjoerg	line_update(bufferline, newline, 0, line + Header_lines);
90924139Sjoerg    }
91024139Sjoerg}
91124139Sjoerg
91224139Sjoergu_endscreen(hi)
91324139Sjoerg
91424139Sjoergregister int hi;
91524139Sjoerg
91624139Sjoerg{
91724139Sjoerg    register int screen_line = hi + Header_lines;
91824139Sjoerg    register int i;
91924139Sjoerg
92024139Sjoerg    if (smart_terminal)
92124139Sjoerg    {
92224139Sjoerg	if (hi < last_hi)
92324139Sjoerg	{
92424139Sjoerg	    /* need to blank the remainder of the screen */
92524139Sjoerg	    /* but only if there is any screen left below this line */
92624139Sjoerg	    if (lastline + 1 < screen_length)
92724139Sjoerg	    {
92824139Sjoerg		/* efficiently move to the end of currently displayed info */
92924139Sjoerg		if (screen_line - lastline < 5)
93024139Sjoerg		{
93124139Sjoerg		    while (lastline < screen_line)
93224139Sjoerg		    {
93324139Sjoerg			putchar('\n');
93424139Sjoerg			lastline++;
93524139Sjoerg		    }
93624139Sjoerg		}
93724139Sjoerg		else
93824139Sjoerg		{
93924139Sjoerg		    Move_to(0, screen_line);
94024139Sjoerg		    lastline = screen_line;
94124139Sjoerg		}
94224139Sjoerg
94324139Sjoerg		if (clear_to_end)
94424139Sjoerg		{
94524139Sjoerg		    /* we can do this the easy way */
94624139Sjoerg		    putcap(clear_to_end);
94724139Sjoerg		}
94824139Sjoerg		else
94924139Sjoerg		{
95024139Sjoerg		    /* use clear_eol on each line */
95124139Sjoerg		    i = hi;
95224139Sjoerg		    while ((void) clear_eol(strlen(&screenbuf[lineindex(i++)])), i < last_hi)
95324139Sjoerg		    {
95424139Sjoerg			putchar('\n');
95524139Sjoerg		    }
95624139Sjoerg		}
95724139Sjoerg	    }
95824139Sjoerg	}
95924139Sjoerg	last_hi = hi;
96024139Sjoerg
96124139Sjoerg	/* move the cursor to a pleasant place */
96224139Sjoerg	Move_to(x_idlecursor, y_idlecursor);
96324139Sjoerg	lastline = y_idlecursor;
96424139Sjoerg    }
96524139Sjoerg    else
96624139Sjoerg    {
96724139Sjoerg	/* separate this display from the next with some vertical room */
96824139Sjoerg	fputs("\n\n", stdout);
96924139Sjoerg    }
97024139Sjoerg}
97124139Sjoerg
97224139Sjoergdisplay_header(t)
97324139Sjoerg
97424139Sjoergint t;
97524139Sjoerg
97624139Sjoerg{
97724139Sjoerg    if (t)
97824139Sjoerg    {
97924139Sjoerg	header_status = ON;
98024139Sjoerg    }
98124139Sjoerg    else if (header_status == ON)
98224139Sjoerg    {
98324139Sjoerg	header_status = ERASE;
98424139Sjoerg    }
98524139Sjoerg}
98624139Sjoerg
98724139Sjoerg/*VARARGS2*/
98824139Sjoergnew_message(type, msgfmt, a1, a2, a3)
98924139Sjoerg
99024139Sjoergint type;
99124139Sjoergchar *msgfmt;
99224139Sjoergcaddr_t a1, a2, a3;
99324139Sjoerg
99424139Sjoerg{
99524139Sjoerg    register int i;
99624139Sjoerg
99724139Sjoerg    /* first, format the message */
99866641Simp    (void) snprintf(next_msg, sizeof(next_msg), msgfmt, a1, a2, a3);
99924139Sjoerg
100024139Sjoerg    if (msglen > 0)
100124139Sjoerg    {
100224139Sjoerg	/* message there already -- can we clear it? */
100324139Sjoerg	if (!overstrike)
100424139Sjoerg	{
100524139Sjoerg	    /* yes -- write it and clear to end */
100624139Sjoerg	    i = strlen(next_msg);
100724139Sjoerg	    if ((type & MT_delayed) == 0)
100824139Sjoerg	    {
100924139Sjoerg		type & MT_standout ? standout(next_msg) :
101024139Sjoerg		                     fputs(next_msg, stdout);
101124139Sjoerg		(void) clear_eol(msglen - i);
101224139Sjoerg		msglen = i;
101324139Sjoerg		next_msg[0] = '\0';
101424139Sjoerg	    }
101524139Sjoerg	}
101624139Sjoerg    }
101724139Sjoerg    else
101824139Sjoerg    {
101924139Sjoerg	if ((type & MT_delayed) == 0)
102024139Sjoerg	{
102124139Sjoerg	    type & MT_standout ? standout(next_msg) : fputs(next_msg, stdout);
102224139Sjoerg	    msglen = strlen(next_msg);
102324139Sjoerg	    next_msg[0] = '\0';
102424139Sjoerg	}
102524139Sjoerg    }
102624139Sjoerg}
102724139Sjoerg
102824139Sjoergclear_message()
102924139Sjoerg
103024139Sjoerg{
103124139Sjoerg    if (clear_eol(msglen) == 1)
103224139Sjoerg    {
103324139Sjoerg	putchar('\r');
103424139Sjoerg    }
103524139Sjoerg}
103624139Sjoerg
103724139Sjoergreadline(buffer, size, numeric)
103824139Sjoerg
103924139Sjoergchar *buffer;
104024139Sjoergint  size;
104124139Sjoergint  numeric;
104224139Sjoerg
104324139Sjoerg{
104424139Sjoerg    register char *ptr = buffer;
104524139Sjoerg    register char ch;
104624139Sjoerg    register char cnt = 0;
104724139Sjoerg    register char maxcnt = 0;
104824139Sjoerg
104924139Sjoerg    /* allow room for null terminator */
105024139Sjoerg    size -= 1;
105124139Sjoerg
105224139Sjoerg    /* read loop */
105324139Sjoerg    while ((fflush(stdout), read(0, ptr, 1) > 0))
105424139Sjoerg    {
105524139Sjoerg	/* newline means we are done */
105624142Sjoerg	if ((ch = *ptr) == '\n' || ch == '\r')
105724139Sjoerg	{
105824139Sjoerg	    break;
105924139Sjoerg	}
106024139Sjoerg
106124139Sjoerg	/* handle special editing characters */
106224139Sjoerg	if (ch == ch_kill)
106324139Sjoerg	{
106424139Sjoerg	    /* kill line -- account for overstriking */
106524139Sjoerg	    if (overstrike)
106624139Sjoerg	    {
106724139Sjoerg		msglen += maxcnt;
106824139Sjoerg	    }
106924139Sjoerg
107024139Sjoerg	    /* return null string */
107124139Sjoerg	    *buffer = '\0';
107224139Sjoerg	    putchar('\r');
107324139Sjoerg	    return(-1);
107424139Sjoerg	}
107524139Sjoerg	else if (ch == ch_erase)
107624139Sjoerg	{
107724139Sjoerg	    /* erase previous character */
107824139Sjoerg	    if (cnt <= 0)
107924139Sjoerg	    {
108024139Sjoerg		/* none to erase! */
108124139Sjoerg		putchar('\7');
108224139Sjoerg	    }
108324139Sjoerg	    else
108424139Sjoerg	    {
108524139Sjoerg		fputs("\b \b", stdout);
108624139Sjoerg		ptr--;
108724139Sjoerg		cnt--;
108824139Sjoerg	    }
108924139Sjoerg	}
109024139Sjoerg	/* check for character validity and buffer overflow */
109124139Sjoerg	else if (cnt == size || (numeric && !isdigit(ch)) ||
109224139Sjoerg		!isprint(ch))
109324139Sjoerg	{
109424139Sjoerg	    /* not legal */
109524139Sjoerg	    putchar('\7');
109624139Sjoerg	}
109724139Sjoerg	else
109824139Sjoerg	{
109924139Sjoerg	    /* echo it and store it in the buffer */
110024139Sjoerg	    putchar(ch);
110124139Sjoerg	    ptr++;
110224139Sjoerg	    cnt++;
110324139Sjoerg	    if (cnt > maxcnt)
110424139Sjoerg	    {
110524139Sjoerg		maxcnt = cnt;
110624139Sjoerg	    }
110724139Sjoerg	}
110824139Sjoerg    }
110924139Sjoerg
111024139Sjoerg    /* all done -- null terminate the string */
111124139Sjoerg    *ptr = '\0';
111224139Sjoerg
111324139Sjoerg    /* account for the extra characters in the message area */
111424139Sjoerg    /* (if terminal overstrikes, remember the furthest they went) */
111524139Sjoerg    msglen += overstrike ? maxcnt : cnt;
111624139Sjoerg
111724139Sjoerg    /* return either inputted number or string length */
111824139Sjoerg    putchar('\r');
111924139Sjoerg    return(cnt == 0 ? -1 : numeric ? atoi(buffer) : cnt);
112024139Sjoerg}
112124139Sjoerg
112224139Sjoerg/* internal support routines */
112324139Sjoerg
112424139Sjoergstatic int string_count(pp)
112524139Sjoerg
112624139Sjoergregister char **pp;
112724139Sjoerg
112824139Sjoerg{
112924139Sjoerg    register int cnt;
113024139Sjoerg
113124139Sjoerg    cnt = 0;
113224139Sjoerg    while (*pp++ != NULL)
113324139Sjoerg    {
113424139Sjoerg	cnt++;
113524139Sjoerg    }
113624139Sjoerg    return(cnt);
113724139Sjoerg}
113824139Sjoerg
113924139Sjoergstatic void summary_format(str, numbers, names)
114024139Sjoerg
114124139Sjoergchar *str;
114224139Sjoergint *numbers;
114324139Sjoergregister char **names;
114424139Sjoerg
114524139Sjoerg{
114624139Sjoerg    register char *p;
114724139Sjoerg    register int num;
114824139Sjoerg    register char *thisname;
114924139Sjoerg    register int useM = No;
115024139Sjoerg
115124139Sjoerg    /* format each number followed by its string */
115224139Sjoerg    p = str;
115324139Sjoerg    while ((thisname = *names++) != NULL)
115424139Sjoerg    {
115524139Sjoerg	/* get the number to format */
115624139Sjoerg	num = *numbers++;
115724139Sjoerg
115824139Sjoerg	/* display only non-zero numbers */
115924139Sjoerg	if (num > 0)
116024139Sjoerg	{
116124139Sjoerg	    /* is this number in kilobytes? */
116224139Sjoerg	    if (thisname[0] == 'K')
116324139Sjoerg	    {
116424139Sjoerg		/* yes: format it as a memory value */
116524139Sjoerg		p = strecpy(p, format_k(num));
116624139Sjoerg
116724139Sjoerg		/* skip over the K, since it was included by format_k */
116824139Sjoerg		p = strecpy(p, thisname+1);
116924139Sjoerg	    }
117024139Sjoerg	    else
117124139Sjoerg	    {
117224139Sjoerg		p = strecpy(p, itoa(num));
117324139Sjoerg		p = strecpy(p, thisname);
117424139Sjoerg	    }
117524139Sjoerg	}
117624139Sjoerg
117724139Sjoerg	/* ignore negative numbers, but display corresponding string */
117824139Sjoerg	else if (num < 0)
117924139Sjoerg	{
118024139Sjoerg	    p = strecpy(p, thisname);
118124139Sjoerg	}
118224139Sjoerg    }
118324139Sjoerg
118424139Sjoerg    /* if the last two characters in the string are ", ", delete them */
118524139Sjoerg    p -= 2;
118624139Sjoerg    if (p >= str && p[0] == ',' && p[1] == ' ')
118724139Sjoerg    {
118824139Sjoerg	*p = '\0';
118924139Sjoerg    }
119024139Sjoerg}
119124139Sjoerg
119224139Sjoergstatic void line_update(old, new, start, line)
119324139Sjoerg
119424139Sjoergregister char *old;
119524139Sjoergregister char *new;
119624139Sjoergint start;
119724139Sjoergint line;
119824139Sjoerg
119924139Sjoerg{
120024139Sjoerg    register int ch;
120124139Sjoerg    register int diff;
120224139Sjoerg    register int newcol = start + 1;
120324139Sjoerg    register int lastcol = start;
120424139Sjoerg    char cursor_on_line = No;
120524139Sjoerg    char *current;
120624139Sjoerg
120724139Sjoerg    /* compare the two strings and only rewrite what has changed */
120824139Sjoerg    current = old;
120924139Sjoerg#ifdef DEBUG
121024139Sjoerg    fprintf(debug, "line_update, starting at %d\n", start);
121124139Sjoerg    fputs(old, debug);
121224139Sjoerg    fputc('\n', debug);
121324139Sjoerg    fputs(new, debug);
121424139Sjoerg    fputs("\n-\n", debug);
121524139Sjoerg#endif
121624139Sjoerg
121724139Sjoerg    /* start things off on the right foot		    */
121824139Sjoerg    /* this is to make sure the invariants get set up right */
121924139Sjoerg    if ((ch = *new++) != *old)
122024139Sjoerg    {
122124139Sjoerg	if (line - lastline == 1 && start == 0)
122224139Sjoerg	{
122324139Sjoerg	    putchar('\n');
122424139Sjoerg	}
122524139Sjoerg	else
122624139Sjoerg	{
122724139Sjoerg	    Move_to(start, line);
122824139Sjoerg	}
122924139Sjoerg	cursor_on_line = Yes;
123024139Sjoerg	putchar(ch);
123124139Sjoerg	*old = ch;
123224139Sjoerg	lastcol = 1;
123324139Sjoerg    }
123424139Sjoerg    old++;
123524139Sjoerg
123624139Sjoerg    /*
123724139Sjoerg     *  main loop -- check each character.  If the old and new aren't the
123824139Sjoerg     *	same, then update the display.  When the distance from the
123924139Sjoerg     *	current cursor position to the new change is small enough,
124024139Sjoerg     *	the characters that belong there are written to move the
124124139Sjoerg     *	cursor over.
124224139Sjoerg     *
124324139Sjoerg     *	Invariants:
124424139Sjoerg     *	    lastcol is the column where the cursor currently is sitting
124524139Sjoerg     *		(always one beyond the end of the last mismatch).
124624139Sjoerg     */
124724139Sjoerg    do		/* yes, a do...while */
124824139Sjoerg    {
124924139Sjoerg	if ((ch = *new++) != *old)
125024139Sjoerg	{
125124139Sjoerg	    /* new character is different from old	  */
125224139Sjoerg	    /* make sure the cursor is on top of this character */
125324139Sjoerg	    diff = newcol - lastcol;
125424139Sjoerg	    if (diff > 0)
125524139Sjoerg	    {
125624139Sjoerg		/* some motion is required--figure out which is shorter */
125724139Sjoerg		if (diff < 6 && cursor_on_line)
125824139Sjoerg		{
125924139Sjoerg		    /* overwrite old stuff--get it out of the old buffer */
126024139Sjoerg		    printf("%.*s", diff, &current[lastcol-start]);
126124139Sjoerg		}
126224139Sjoerg		else
126324139Sjoerg		{
126424139Sjoerg		    /* use cursor addressing */
126524139Sjoerg		    Move_to(newcol, line);
126624139Sjoerg		    cursor_on_line = Yes;
126724139Sjoerg		}
126824139Sjoerg		/* remember where the cursor is */
126924139Sjoerg		lastcol = newcol + 1;
127024139Sjoerg	    }
127124139Sjoerg	    else
127224139Sjoerg	    {
127324139Sjoerg		/* already there, update position */
127424139Sjoerg		lastcol++;
127524139Sjoerg	    }
127624139Sjoerg
127724139Sjoerg	    /* write what we need to */
127824139Sjoerg	    if (ch == '\0')
127924139Sjoerg	    {
128024139Sjoerg		/* at the end--terminate with a clear-to-end-of-line */
128124139Sjoerg		(void) clear_eol(strlen(old));
128224139Sjoerg	    }
128324139Sjoerg	    else
128424139Sjoerg	    {
128524139Sjoerg		/* write the new character */
128624139Sjoerg		putchar(ch);
128724139Sjoerg	    }
128824139Sjoerg	    /* put the new character in the screen buffer */
128924139Sjoerg	    *old = ch;
129024139Sjoerg	}
129124139Sjoerg
129224139Sjoerg	/* update working column and screen buffer pointer */
129324139Sjoerg	newcol++;
129424139Sjoerg	old++;
129524139Sjoerg
129624139Sjoerg    } while (ch != '\0');
129724139Sjoerg
129824139Sjoerg    /* zero out the rest of the line buffer -- MUST BE DONE! */
129924139Sjoerg    diff = display_width - newcol;
130024139Sjoerg    if (diff > 0)
130124139Sjoerg    {
130224139Sjoerg	memzero(old, diff);
130324139Sjoerg    }
130424139Sjoerg
130524139Sjoerg    /* remember where the current line is */
130624139Sjoerg    if (cursor_on_line)
130724139Sjoerg    {
130824139Sjoerg	lastline = line;
130924139Sjoerg    }
131024139Sjoerg}
131124139Sjoerg
131224139Sjoerg/*
131324139Sjoerg *  printable(str) - make the string pointed to by "str" into one that is
131424139Sjoerg *	printable (i.e.: all ascii), by converting all non-printable
131524139Sjoerg *	characters into '?'.  Replacements are done in place and a pointer
131624139Sjoerg *	to the original buffer is returned.
131724139Sjoerg */
131824139Sjoerg
131924139Sjoergchar *printable(str)
132024139Sjoerg
132124139Sjoergchar *str;
132224139Sjoerg
132324139Sjoerg{
132424139Sjoerg    register char *ptr;
132524139Sjoerg    register char ch;
132624139Sjoerg
132724139Sjoerg    ptr = str;
132824139Sjoerg    while ((ch = *ptr) != '\0')
132924139Sjoerg    {
133024139Sjoerg	if (!isprint(ch))
133124139Sjoerg	{
133224139Sjoerg	    *ptr = '?';
133324139Sjoerg	}
133424139Sjoerg	ptr++;
133524139Sjoerg    }
133624139Sjoerg    return(str);
133724139Sjoerg}
133842447Sobrien
133942447Sobrieni_uptime(bt, tod)
134042447Sobrien
134142447Sobrienstruct timeval* bt;
134242447Sobrientime_t *tod;
134342447Sobrien
134442447Sobrien{
134542447Sobrien    time_t uptime;
134642447Sobrien    int days, hrs, mins, secs;
134742447Sobrien
134842447Sobrien    if (bt->tv_sec != -1) {
134942447Sobrien	uptime = *tod - bt->tv_sec;
135042447Sobrien	days = uptime / 86400;
135142447Sobrien	uptime %= 86400;
135242447Sobrien	hrs = uptime / 3600;
135342447Sobrien	uptime %= 3600;
135442447Sobrien	mins = uptime / 60;
135542447Sobrien	secs = uptime % 60;
135642447Sobrien
135742447Sobrien	/*
135842447Sobrien	 *  Display the uptime.
135942447Sobrien	 */
136042447Sobrien
136142447Sobrien	if (smart_terminal)
136242447Sobrien	{
136342447Sobrien	    Move_to((screen_width - 24) - (days > 9 ? 1 : 0), 0);
136442447Sobrien	}
136542447Sobrien	else
136642447Sobrien	{
136742447Sobrien	    fputs(" ", stdout);
136842447Sobrien	}
136942447Sobrien	printf(" up %d+%02d:%02d:%02d", days, hrs, mins, secs);
137042447Sobrien    }
137142447Sobrien}
1372