display.c revision 146344
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: head/contrib/top/display.c 146344 2005-05-18 13:48:33Z keramida $
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;
6924142Sjoergstatic char **swap_names;
7024139Sjoerg
7124139Sjoergstatic int num_procstates;
7224139Sjoergstatic int num_cpustates;
7324139Sjoergstatic int num_memory;
7424142Sjoergstatic int num_swap;
7524139Sjoerg
7624139Sjoergstatic int *lprocstates;
7724139Sjoergstatic int *lcpustates;
7824139Sjoergstatic int *lmemory;
7924142Sjoergstatic int *lswap;
8024139Sjoerg
8124139Sjoergstatic int *cpustate_columns;
8224139Sjoergstatic int cpustate_total_length;
8324139Sjoerg
8424139Sjoergstatic enum { OFF, ON, ERASE } header_status = ON;
8524139Sjoerg
8624139Sjoergstatic int string_count();
8724139Sjoergstatic void summary_format();
8824139Sjoergstatic void line_update();
8924139Sjoerg
9024139Sjoergint display_resize()
9124139Sjoerg
9224139Sjoerg{
9324139Sjoerg    register int lines;
9424139Sjoerg
9524139Sjoerg    /* first, deallocate any previous buffer that may have been there */
9624139Sjoerg    if (screenbuf != NULL)
9724139Sjoerg    {
9824139Sjoerg	free(screenbuf);
9924139Sjoerg    }
10024139Sjoerg
10124139Sjoerg    /* calculate the current dimensions */
10224139Sjoerg    /* if operating in "dumb" mode, we only need one line */
10324139Sjoerg    lines = smart_terminal ? screen_length - Header_lines : 1;
10424139Sjoerg
105101692Sdwmalone    if (lines < 0)
106101692Sdwmalone	lines = 0;
10724139Sjoerg    /* we don't want more than MAX_COLS columns, since the machine-dependent
10824139Sjoerg       modules make static allocations based on MAX_COLS and we don't want
10924139Sjoerg       to run off the end of their buffers */
11024139Sjoerg    display_width = screen_width;
11124139Sjoerg    if (display_width >= MAX_COLS)
11224139Sjoerg    {
11324139Sjoerg	display_width = MAX_COLS - 1;
11424139Sjoerg    }
11524139Sjoerg
11624139Sjoerg    /* now, allocate space for the screen buffer */
11724139Sjoerg    screenbuf = (char *)malloc(lines * display_width);
11824139Sjoerg    if (screenbuf == (char *)NULL)
11924139Sjoerg    {
12024139Sjoerg	/* oops! */
12124139Sjoerg	return(-1);
12224139Sjoerg    }
12324139Sjoerg
12424139Sjoerg    /* return number of lines available */
12524139Sjoerg    /* for dumb terminals, pretend like we can show any amount */
12624139Sjoerg    return(smart_terminal ? lines : Largest);
12724139Sjoerg}
12824139Sjoerg
12924139Sjoergint display_init(statics)
13024139Sjoerg
13124139Sjoergstruct statics *statics;
13224139Sjoerg
13324139Sjoerg{
13424139Sjoerg    register int lines;
13524139Sjoerg    register char **pp;
13624139Sjoerg    register int *ip;
13724139Sjoerg    register int i;
13824139Sjoerg
13924139Sjoerg    /* call resize to do the dirty work */
14024139Sjoerg    lines = display_resize();
14124139Sjoerg
14224139Sjoerg    /* only do the rest if we need to */
14324139Sjoerg    if (lines > -1)
14424139Sjoerg    {
14524139Sjoerg	/* save pointers and allocate space for names */
14624139Sjoerg	procstate_names = statics->procstate_names;
14724139Sjoerg	num_procstates = string_count(procstate_names);
14824139Sjoerg	lprocstates = (int *)malloc(num_procstates * sizeof(int));
14924139Sjoerg
15024139Sjoerg	cpustate_names = statics->cpustate_names;
15124142Sjoerg
15224142Sjoerg	swap_names = statics->swap_names;
15324142Sjoerg	num_swap = string_count(swap_names);
15424142Sjoerg	lswap = (int *)malloc(num_swap * sizeof(int));
15524139Sjoerg	num_cpustates = string_count(cpustate_names);
15624139Sjoerg	lcpustates = (int *)malloc(num_cpustates * sizeof(int));
15724139Sjoerg	cpustate_columns = (int *)malloc(num_cpustates * sizeof(int));
15824139Sjoerg
15924139Sjoerg	memory_names = statics->memory_names;
16024139Sjoerg	num_memory = string_count(memory_names);
16124139Sjoerg	lmemory = (int *)malloc(num_memory * sizeof(int));
16224139Sjoerg
16324139Sjoerg	/* calculate starting columns where needed */
16424139Sjoerg	cpustate_total_length = 0;
16524139Sjoerg	pp = cpustate_names;
16624139Sjoerg	ip = cpustate_columns;
16724139Sjoerg	while (*pp != NULL)
16824139Sjoerg	{
16989758Sdwmalone	    *ip++ = cpustate_total_length;
17024139Sjoerg	    if ((i = strlen(*pp++)) > 0)
17124139Sjoerg	    {
17224139Sjoerg		cpustate_total_length += i + 8;
17324139Sjoerg	    }
17424139Sjoerg	}
17524139Sjoerg    }
17624139Sjoerg
17724139Sjoerg    /* return number of lines available */
17824139Sjoerg    return(lines);
17924139Sjoerg}
18024139Sjoerg
18124139Sjoergi_loadave(mpid, avenrun)
18224139Sjoerg
18324139Sjoergint mpid;
18424139Sjoergdouble *avenrun;
18524139Sjoerg
18624139Sjoerg{
18724139Sjoerg    register int i;
18824139Sjoerg
18924139Sjoerg    /* i_loadave also clears the screen, since it is first */
19024139Sjoerg    clear();
19124139Sjoerg
19224139Sjoerg    /* mpid == -1 implies this system doesn't have an _mpid */
19324139Sjoerg    if (mpid != -1)
19424139Sjoerg    {
19524139Sjoerg	printf("last pid: %5d;  ", mpid);
19624139Sjoerg    }
19724139Sjoerg
19824139Sjoerg    printf("load averages");
19924139Sjoerg
20024139Sjoerg    for (i = 0; i < 3; i++)
20124139Sjoerg    {
20224139Sjoerg	printf("%c %5.2f",
20324139Sjoerg	    i == 0 ? ':' : ',',
20424139Sjoerg	    avenrun[i]);
20524139Sjoerg    }
20624139Sjoerg    lmpid = mpid;
20724139Sjoerg}
20824139Sjoerg
20924139Sjoergu_loadave(mpid, avenrun)
21024139Sjoerg
21124139Sjoergint mpid;
21224139Sjoergdouble *avenrun;
21324139Sjoerg
21424139Sjoerg{
21524139Sjoerg    register int i;
21624139Sjoerg
21724139Sjoerg    if (mpid != -1)
21824139Sjoerg    {
21924139Sjoerg	/* change screen only when value has really changed */
22024139Sjoerg	if (mpid != lmpid)
22124139Sjoerg	{
22224139Sjoerg	    Move_to(x_lastpid, y_lastpid);
22324139Sjoerg	    printf("%5d", mpid);
22424139Sjoerg	    lmpid = mpid;
22524139Sjoerg	}
22624139Sjoerg
22724139Sjoerg	/* i remembers x coordinate to move to */
22824139Sjoerg	i = x_loadave;
22924139Sjoerg    }
23024139Sjoerg    else
23124139Sjoerg    {
23224139Sjoerg	i = x_loadave_nompid;
23324139Sjoerg    }
23424139Sjoerg
23524139Sjoerg    /* move into position for load averages */
23624139Sjoerg    Move_to(i, y_loadave);
23724139Sjoerg
23824139Sjoerg    /* display new load averages */
23924139Sjoerg    /* we should optimize this and only display changes */
24024139Sjoerg    for (i = 0; i < 3; i++)
24124139Sjoerg    {
24224139Sjoerg	printf("%s%5.2f",
24324139Sjoerg	    i == 0 ? "" : ", ",
24424139Sjoerg	    avenrun[i]);
24524139Sjoerg    }
24624139Sjoerg}
24724139Sjoerg
24824139Sjoergi_timeofday(tod)
24924139Sjoerg
25024139Sjoergtime_t *tod;
25124139Sjoerg
25224139Sjoerg{
25324139Sjoerg    /*
25424139Sjoerg     *  Display the current time.
25524139Sjoerg     *  "ctime" always returns a string that looks like this:
25624139Sjoerg     *
25724139Sjoerg     *	Sun Sep 16 01:03:52 1973
25824139Sjoerg     *      012345678901234567890123
25924139Sjoerg     *	          1         2
26024139Sjoerg     *
26124139Sjoerg     *  We want indices 11 thru 18 (length 8).
26224139Sjoerg     */
26324139Sjoerg
26424139Sjoerg    if (smart_terminal)
26524139Sjoerg    {
26624139Sjoerg	Move_to(screen_width - 8, 0);
26724139Sjoerg    }
26824139Sjoerg    else
26924139Sjoerg    {
27024139Sjoerg	fputs("    ", stdout);
27124139Sjoerg    }
27224139Sjoerg#ifdef DEBUG
27324139Sjoerg    {
27424139Sjoerg	char *foo;
27524139Sjoerg	foo = ctime(tod);
27624139Sjoerg	fputs(foo, stdout);
27724139Sjoerg    }
27824139Sjoerg#endif
27924139Sjoerg    printf("%-8.8s\n", &(ctime(tod)[11]));
28024139Sjoerg    lastline = 1;
28124139Sjoerg}
28224139Sjoerg
28324139Sjoergstatic int ltotal = 0;
28489758Sdwmalonestatic char procstates_buffer[MAX_COLS];
28524139Sjoerg
28624139Sjoerg/*
28724139Sjoerg *  *_procstates(total, brkdn, names) - print the process summary line
28824139Sjoerg *
28924139Sjoerg *  Assumptions:  cursor is at the beginning of the line on entry
29024139Sjoerg *		  lastline is valid
29124139Sjoerg */
29224139Sjoerg
29324139Sjoergi_procstates(total, brkdn)
29424139Sjoerg
29524139Sjoergint total;
29624139Sjoergint *brkdn;
29724139Sjoerg
29824139Sjoerg{
29924139Sjoerg    register int i;
30024139Sjoerg
30124139Sjoerg    /* write current number of processes and remember the value */
30224139Sjoerg    printf("%d processes:", total);
30324139Sjoerg    ltotal = total;
30424139Sjoerg
30524139Sjoerg    /* put out enough spaces to get to column 15 */
30624139Sjoerg    i = digits(total);
30724139Sjoerg    while (i++ < 4)
30824139Sjoerg    {
30924139Sjoerg	putchar(' ');
31024139Sjoerg    }
31124139Sjoerg
31224139Sjoerg    /* format and print the process state summary */
31324139Sjoerg    summary_format(procstates_buffer, brkdn, procstate_names);
31424139Sjoerg    fputs(procstates_buffer, stdout);
31524139Sjoerg
31624139Sjoerg    /* save the numbers for next time */
31724139Sjoerg    memcpy(lprocstates, brkdn, num_procstates * sizeof(int));
31824139Sjoerg}
31924139Sjoerg
32024139Sjoergu_procstates(total, brkdn)
32124139Sjoerg
32224139Sjoergint total;
32324139Sjoergint *brkdn;
32424139Sjoerg
32524139Sjoerg{
32689758Sdwmalone    static char new[MAX_COLS];
32724139Sjoerg    register int i;
32824139Sjoerg
32924139Sjoerg    /* update number of processes only if it has changed */
33024139Sjoerg    if (ltotal != total)
33124139Sjoerg    {
33224139Sjoerg	/* move and overwrite */
33324139Sjoerg#if (x_procstate == 0)
33424139Sjoerg	Move_to(x_procstate, y_procstate);
33524139Sjoerg#else
33624139Sjoerg	/* cursor is already there...no motion needed */
33724139Sjoerg	/* assert(lastline == 1); */
33824139Sjoerg#endif
33924139Sjoerg	printf("%d", total);
34024139Sjoerg
34124139Sjoerg	/* if number of digits differs, rewrite the label */
34224139Sjoerg	if (digits(total) != digits(ltotal))
34324139Sjoerg	{
34424139Sjoerg	    fputs(" processes:", stdout);
34524139Sjoerg	    /* put out enough spaces to get to column 15 */
34624139Sjoerg	    i = digits(total);
34724139Sjoerg	    while (i++ < 4)
34824139Sjoerg	    {
34924139Sjoerg		putchar(' ');
35024139Sjoerg	    }
35124139Sjoerg	    /* cursor may end up right where we want it!!! */
35224139Sjoerg	}
35324139Sjoerg
35424139Sjoerg	/* save new total */
35524139Sjoerg	ltotal = total;
35624139Sjoerg    }
35724139Sjoerg
35824139Sjoerg    /* see if any of the state numbers has changed */
35924139Sjoerg    if (memcmp(lprocstates, brkdn, num_procstates * sizeof(int)) != 0)
36024139Sjoerg    {
36124139Sjoerg	/* format and update the line */
36224139Sjoerg	summary_format(new, brkdn, procstate_names);
36324139Sjoerg	line_update(procstates_buffer, new, x_brkdn, y_brkdn);
36424139Sjoerg	memcpy(lprocstates, brkdn, num_procstates * sizeof(int));
36524139Sjoerg    }
36624139Sjoerg}
36724139Sjoerg
36824139Sjoerg/*
36924139Sjoerg *  *_cpustates(states, names) - print the cpu state percentages
37024139Sjoerg *
37124139Sjoerg *  Assumptions:  cursor is on the PREVIOUS line
37224139Sjoerg */
37324139Sjoerg
37424139Sjoergstatic int cpustates_column;
37524139Sjoerg
37624139Sjoerg/* cpustates_tag() calculates the correct tag to use to label the line */
37724139Sjoerg
37824139Sjoergchar *cpustates_tag()
37924139Sjoerg
38024139Sjoerg{
38124139Sjoerg    register char *use;
38224139Sjoerg
38324139Sjoerg    static char *short_tag = "CPU: ";
38424139Sjoerg    static char *long_tag = "CPU states: ";
38524139Sjoerg
38624139Sjoerg    /* if length + strlen(long_tag) >= screen_width, then we have to
38724139Sjoerg       use the shorter tag (we subtract 2 to account for ": ") */
38824139Sjoerg    if (cpustate_total_length + (int)strlen(long_tag) - 2 >= screen_width)
38924139Sjoerg    {
39024139Sjoerg	use = short_tag;
39124139Sjoerg    }
39224139Sjoerg    else
39324139Sjoerg    {
39424139Sjoerg	use = long_tag;
39524139Sjoerg    }
39624139Sjoerg
39724139Sjoerg    /* set cpustates_column accordingly then return result */
39824139Sjoerg    cpustates_column = strlen(use);
39924139Sjoerg    return(use);
40024139Sjoerg}
40124139Sjoerg
40224139Sjoergi_cpustates(states)
40324139Sjoerg
40424139Sjoergregister int *states;
40524139Sjoerg
40624139Sjoerg{
40724139Sjoerg    register int i = 0;
40824139Sjoerg    register int value;
40924139Sjoerg    register char **names = cpustate_names;
41024139Sjoerg    register char *thisname;
41124139Sjoerg
41224139Sjoerg    /* print tag and bump lastline */
41324139Sjoerg    printf("\n%s", cpustates_tag());
41424139Sjoerg    lastline++;
41524139Sjoerg
41624139Sjoerg    /* now walk thru the names and print the line */
41724139Sjoerg    while ((thisname = *names++) != NULL)
41824139Sjoerg    {
41924139Sjoerg	if (*thisname != '\0')
42024139Sjoerg	{
42124139Sjoerg	    /* retrieve the value and remember it */
42224139Sjoerg	    value = *states++;
42324139Sjoerg
42424139Sjoerg	    /* if percentage is >= 1000, print it as 100% */
42524139Sjoerg	    printf((value >= 1000 ? "%s%4.0f%% %s" : "%s%4.1f%% %s"),
42624139Sjoerg		   i++ == 0 ? "" : ", ",
42724139Sjoerg		   ((float)value)/10.,
42824139Sjoerg		   thisname);
42924139Sjoerg	}
43024139Sjoerg    }
43124139Sjoerg
43224139Sjoerg    /* copy over values into "last" array */
43324139Sjoerg    memcpy(lcpustates, states, num_cpustates * sizeof(int));
43424139Sjoerg}
43524139Sjoerg
43624139Sjoergu_cpustates(states)
43724139Sjoerg
43824139Sjoergregister int *states;
43924139Sjoerg
44024139Sjoerg{
44124139Sjoerg    register int value;
44224139Sjoerg    register char **names = cpustate_names;
44324139Sjoerg    register char *thisname;
44424139Sjoerg    register int *lp;
44524139Sjoerg    register int *colp;
44624139Sjoerg
44724139Sjoerg    Move_to(cpustates_column, y_cpustates);
44824139Sjoerg    lastline = y_cpustates;
44924139Sjoerg    lp = lcpustates;
45024139Sjoerg    colp = cpustate_columns;
45124139Sjoerg
45224139Sjoerg    /* we could be much more optimal about this */
45324139Sjoerg    while ((thisname = *names++) != NULL)
45424139Sjoerg    {
45524139Sjoerg	if (*thisname != '\0')
45624139Sjoerg	{
45724139Sjoerg	    /* did the value change since last time? */
45824139Sjoerg	    if (*lp != *states)
45924139Sjoerg	    {
46024139Sjoerg		/* yes, move and change */
46124139Sjoerg		Move_to(cpustates_column + *colp, y_cpustates);
46224139Sjoerg		lastline = y_cpustates;
46324139Sjoerg
46424139Sjoerg		/* retrieve value and remember it */
46524139Sjoerg		value = *states;
46624139Sjoerg
46724139Sjoerg		/* if percentage is >= 1000, print it as 100% */
46824139Sjoerg		printf((value >= 1000 ? "%4.0f" : "%4.1f"),
46924139Sjoerg		       ((double)value)/10.);
47024139Sjoerg
47124139Sjoerg		/* remember it for next time */
47289758Sdwmalone		*lp = value;
47324139Sjoerg	    }
47424139Sjoerg	}
47524139Sjoerg
47624139Sjoerg	/* increment and move on */
47724139Sjoerg	lp++;
47824139Sjoerg	states++;
47924139Sjoerg	colp++;
48024139Sjoerg    }
48124139Sjoerg}
48224139Sjoerg
48324139Sjoergz_cpustates()
48424139Sjoerg
48524139Sjoerg{
48624139Sjoerg    register int i = 0;
48724139Sjoerg    register char **names = cpustate_names;
48824139Sjoerg    register char *thisname;
48924139Sjoerg    register int *lp;
49024139Sjoerg
49124139Sjoerg    /* show tag and bump lastline */
49224139Sjoerg    printf("\n%s", cpustates_tag());
49324139Sjoerg    lastline++;
49424139Sjoerg
49524139Sjoerg    while ((thisname = *names++) != NULL)
49624139Sjoerg    {
49724139Sjoerg	if (*thisname != '\0')
49824139Sjoerg	{
49924139Sjoerg	    printf("%s    %% %s", i++ == 0 ? "" : ", ", thisname);
50024139Sjoerg	}
50124139Sjoerg    }
50224139Sjoerg
50324139Sjoerg    /* fill the "last" array with all -1s, to insure correct updating */
50424139Sjoerg    lp = lcpustates;
50524139Sjoerg    i = num_cpustates;
50624139Sjoerg    while (--i >= 0)
50724139Sjoerg    {
50824139Sjoerg	*lp++ = -1;
50924139Sjoerg    }
51024139Sjoerg}
51124139Sjoerg
51224139Sjoerg/*
51324139Sjoerg *  *_memory(stats) - print "Memory: " followed by the memory summary string
51424139Sjoerg *
51524139Sjoerg *  Assumptions:  cursor is on "lastline"
51624139Sjoerg *                for i_memory ONLY: cursor is on the previous line
51724139Sjoerg */
51824139Sjoerg
51924139Sjoergchar memory_buffer[MAX_COLS];
52024139Sjoerg
52124139Sjoergi_memory(stats)
52224139Sjoerg
52324139Sjoergint *stats;
52424139Sjoerg
52524139Sjoerg{
52624142Sjoerg    fputs("\nMem: ", stdout);
52724139Sjoerg    lastline++;
52824139Sjoerg
52924139Sjoerg    /* format and print the memory summary */
53024139Sjoerg    summary_format(memory_buffer, stats, memory_names);
53124139Sjoerg    fputs(memory_buffer, stdout);
53224139Sjoerg}
53324139Sjoerg
53424139Sjoergu_memory(stats)
53524139Sjoerg
53624139Sjoergint *stats;
53724139Sjoerg
53824139Sjoerg{
53924139Sjoerg    static char new[MAX_COLS];
54024139Sjoerg
54124139Sjoerg    /* format the new line */
54224139Sjoerg    summary_format(new, stats, memory_names);
54324139Sjoerg    line_update(memory_buffer, new, x_mem, y_mem);
54424139Sjoerg}
54524139Sjoerg
54624139Sjoerg/*
54724142Sjoerg *  *_swap(stats) - print "Swap: " followed by the swap summary string
54824142Sjoerg *
54924142Sjoerg *  Assumptions:  cursor is on "lastline"
55024142Sjoerg *                for i_swap ONLY: cursor is on the previous line
55124142Sjoerg */
55224142Sjoerg
55324142Sjoergchar swap_buffer[MAX_COLS];
55424142Sjoerg
55524142Sjoergi_swap(stats)
55624142Sjoerg
55724142Sjoergint *stats;
55824142Sjoerg
55924142Sjoerg{
56024142Sjoerg    fputs("\nSwap: ", stdout);
56124142Sjoerg    lastline++;
56224142Sjoerg
56324142Sjoerg    /* format and print the swap summary */
56424142Sjoerg    summary_format(swap_buffer, stats, swap_names);
56524142Sjoerg    fputs(swap_buffer, stdout);
56624142Sjoerg}
56724142Sjoerg
56824142Sjoergu_swap(stats)
56924142Sjoerg
57024142Sjoergint *stats;
57124142Sjoerg
57224142Sjoerg{
57324142Sjoerg    static char new[MAX_COLS];
57424142Sjoerg
57524142Sjoerg    /* format the new line */
57624142Sjoerg    summary_format(new, stats, swap_names);
57724142Sjoerg    line_update(swap_buffer, new, x_swap, y_swap);
57824142Sjoerg}
57924142Sjoerg
58024142Sjoerg/*
58124139Sjoerg *  *_message() - print the next pending message line, or erase the one
58224139Sjoerg *                that is there.
58324139Sjoerg *
58424139Sjoerg *  Note that u_message is (currently) the same as i_message.
58524139Sjoerg *
58624139Sjoerg *  Assumptions:  lastline is consistent
58724139Sjoerg */
58824139Sjoerg
58924139Sjoerg/*
59024139Sjoerg *  i_message is funny because it gets its message asynchronously (with
59124139Sjoerg *	respect to screen updates).
59224139Sjoerg */
59324139Sjoerg
59424139Sjoergstatic char next_msg[MAX_COLS + 5];
59524139Sjoergstatic int msglen = 0;
59624139Sjoerg/* Invariant: msglen is always the length of the message currently displayed
59724139Sjoerg   on the screen (even when next_msg doesn't contain that message). */
59824139Sjoerg
59924139Sjoergi_message()
60024139Sjoerg
60124139Sjoerg{
60224139Sjoerg    while (lastline < y_message)
60324139Sjoerg    {
60424139Sjoerg	fputc('\n', stdout);
60524139Sjoerg	lastline++;
60624139Sjoerg    }
60724139Sjoerg    if (next_msg[0] != '\0')
60824139Sjoerg    {
60924139Sjoerg	standout(next_msg);
61024139Sjoerg	msglen = strlen(next_msg);
61124139Sjoerg	next_msg[0] = '\0';
61224139Sjoerg    }
61324139Sjoerg    else if (msglen > 0)
61424139Sjoerg    {
61524139Sjoerg	(void) clear_eol(msglen);
61624139Sjoerg	msglen = 0;
61724139Sjoerg    }
61824139Sjoerg}
61924139Sjoerg
62024139Sjoergu_message()
62124139Sjoerg
62224139Sjoerg{
62324139Sjoerg    i_message();
62424139Sjoerg}
62524139Sjoerg
62624139Sjoergstatic int header_length;
62724139Sjoerg
62824139Sjoerg/*
629146344Skeramida * Trim a header string to the current display width and return a newly
630146344Skeramida * allocated area with the trimmed header.
631146344Skeramida */
632146344Skeramida
633146344Skeramidachar *
634146344Skeramidatrim_header(text)
635146344Skeramida
636146344Skeramidachar *text;
637146344Skeramida
638146344Skeramida{
639146344Skeramida	char *s;
640146344Skeramida	int width;
641146344Skeramida
642146344Skeramida	s = NULL;
643146344Skeramida	width = display_width;
644146344Skeramida	header_length = strlen(text);
645146344Skeramida	if (header_length >= width) {
646146344Skeramida		s = malloc((width + 1) * sizeof(char));
647146344Skeramida		if (s == NULL)
648146344Skeramida			return (NULL);
649146344Skeramida		strncpy(s, text, width);
650146344Skeramida		s[width] = '\0';
651146344Skeramida	}
652146344Skeramida	return (s);
653146344Skeramida}
654146344Skeramida
655146344Skeramida/*
65624139Sjoerg *  *_header(text) - print the header for the process area
65724139Sjoerg *
65824139Sjoerg *  Assumptions:  cursor is on the previous line and lastline is consistent
65924139Sjoerg */
66024139Sjoerg
66124139Sjoergi_header(text)
66224139Sjoerg
66324139Sjoergchar *text;
66424139Sjoerg
66524139Sjoerg{
666146344Skeramida    char *s;
667146344Skeramida
668146344Skeramida    s = trim_header(text);
669146344Skeramida    if (s != NULL)
670146344Skeramida	text = s;
671146344Skeramida
67224139Sjoerg    if (header_status == ON)
67324139Sjoerg    {
67424139Sjoerg	putchar('\n');
67524139Sjoerg	fputs(text, stdout);
67624139Sjoerg	lastline++;
67724139Sjoerg    }
67824139Sjoerg    else if (header_status == ERASE)
67924139Sjoerg    {
68024139Sjoerg	header_status = OFF;
68124139Sjoerg    }
682146344Skeramida    free(s);
68324139Sjoerg}
68424139Sjoerg
68524139Sjoerg/*ARGSUSED*/
68624139Sjoergu_header(text)
68724139Sjoerg
68824139Sjoergchar *text;		/* ignored */
68924139Sjoerg
69024139Sjoerg{
691146344Skeramida    char *s;
692146344Skeramida
693146344Skeramida    s = trim_header(text);
694146344Skeramida    if (s != NULL)
695146344Skeramida	text = s;
696146344Skeramida
69724139Sjoerg    if (header_status == ERASE)
69824139Sjoerg    {
69924139Sjoerg	putchar('\n');
70024139Sjoerg	lastline++;
70124139Sjoerg	clear_eol(header_length);
70224139Sjoerg	header_status = OFF;
70324139Sjoerg    }
704146344Skeramida    free(s);
70524139Sjoerg}
70624139Sjoerg
70724139Sjoerg/*
70824139Sjoerg *  *_process(line, thisline) - print one process line
70924139Sjoerg *
71024139Sjoerg *  Assumptions:  lastline is consistent
71124139Sjoerg */
71224139Sjoerg
71324139Sjoergi_process(line, thisline)
71424139Sjoerg
71524139Sjoergint line;
71624139Sjoergchar *thisline;
71724139Sjoerg
71824139Sjoerg{
71924139Sjoerg    register char *p;
72024139Sjoerg    register char *base;
72124139Sjoerg
72224139Sjoerg    /* make sure we are on the correct line */
72324139Sjoerg    while (lastline < y_procs + line)
72424139Sjoerg    {
72524139Sjoerg	putchar('\n');
72624139Sjoerg	lastline++;
72724139Sjoerg    }
72824139Sjoerg
72924139Sjoerg    /* truncate the line to conform to our current screen width */
73024139Sjoerg    thisline[display_width] = '\0';
73124139Sjoerg
73224139Sjoerg    /* write the line out */
73324139Sjoerg    fputs(thisline, stdout);
73424139Sjoerg
73524139Sjoerg    /* copy it in to our buffer */
73624139Sjoerg    base = smart_terminal ? screenbuf + lineindex(line) : screenbuf;
73724139Sjoerg    p = strecpy(base, thisline);
73824139Sjoerg
73924139Sjoerg    /* zero fill the rest of it */
74024139Sjoerg    memzero(p, display_width - (p - base));
74124139Sjoerg}
74224139Sjoerg
74324139Sjoergu_process(line, newline)
74424139Sjoerg
74524139Sjoergint line;
74624139Sjoergchar *newline;
74724139Sjoerg
74824139Sjoerg{
74924139Sjoerg    register char *optr;
75024139Sjoerg    register int screen_line = line + Header_lines;
75124139Sjoerg    register char *bufferline;
75224139Sjoerg
75324139Sjoerg    /* remember a pointer to the current line in the screen buffer */
75424139Sjoerg    bufferline = &screenbuf[lineindex(line)];
75524139Sjoerg
75624139Sjoerg    /* truncate the line to conform to our current screen width */
75724139Sjoerg    newline[display_width] = '\0';
75824139Sjoerg
75924139Sjoerg    /* is line higher than we went on the last display? */
76024139Sjoerg    if (line >= last_hi)
76124139Sjoerg    {
76224139Sjoerg	/* yes, just ignore screenbuf and write it out directly */
76324139Sjoerg	/* get positioned on the correct line */
76424139Sjoerg	if (screen_line - lastline == 1)
76524139Sjoerg	{
76624139Sjoerg	    putchar('\n');
76724139Sjoerg	    lastline++;
76824139Sjoerg	}
76924139Sjoerg	else
77024139Sjoerg	{
77124139Sjoerg	    Move_to(0, screen_line);
77224139Sjoerg	    lastline = screen_line;
77324139Sjoerg	}
77424139Sjoerg
77524139Sjoerg	/* now write the line */
77624139Sjoerg	fputs(newline, stdout);
77724139Sjoerg
77824139Sjoerg	/* copy it in to the buffer */
77924139Sjoerg	optr = strecpy(bufferline, newline);
78024139Sjoerg
78124139Sjoerg	/* zero fill the rest of it */
78224139Sjoerg	memzero(optr, display_width - (optr - bufferline));
78324139Sjoerg    }
78424139Sjoerg    else
78524139Sjoerg    {
78624139Sjoerg	line_update(bufferline, newline, 0, line + Header_lines);
78724139Sjoerg    }
78824139Sjoerg}
78924139Sjoerg
79024139Sjoergu_endscreen(hi)
79124139Sjoerg
79224139Sjoergregister int hi;
79324139Sjoerg
79424139Sjoerg{
79524139Sjoerg    register int screen_line = hi + Header_lines;
79624139Sjoerg    register int i;
79724139Sjoerg
79824139Sjoerg    if (smart_terminal)
79924139Sjoerg    {
80024139Sjoerg	if (hi < last_hi)
80124139Sjoerg	{
80224139Sjoerg	    /* need to blank the remainder of the screen */
80324139Sjoerg	    /* but only if there is any screen left below this line */
80424139Sjoerg	    if (lastline + 1 < screen_length)
80524139Sjoerg	    {
80624139Sjoerg		/* efficiently move to the end of currently displayed info */
80724139Sjoerg		if (screen_line - lastline < 5)
80824139Sjoerg		{
80924139Sjoerg		    while (lastline < screen_line)
81024139Sjoerg		    {
81124139Sjoerg			putchar('\n');
81224139Sjoerg			lastline++;
81324139Sjoerg		    }
81424139Sjoerg		}
81524139Sjoerg		else
81624139Sjoerg		{
81724139Sjoerg		    Move_to(0, screen_line);
81824139Sjoerg		    lastline = screen_line;
81924139Sjoerg		}
82024139Sjoerg
82124139Sjoerg		if (clear_to_end)
82224139Sjoerg		{
82324139Sjoerg		    /* we can do this the easy way */
82424139Sjoerg		    putcap(clear_to_end);
82524139Sjoerg		}
82624139Sjoerg		else
82724139Sjoerg		{
82824139Sjoerg		    /* use clear_eol on each line */
82924139Sjoerg		    i = hi;
83024139Sjoerg		    while ((void) clear_eol(strlen(&screenbuf[lineindex(i++)])), i < last_hi)
83124139Sjoerg		    {
83224139Sjoerg			putchar('\n');
83324139Sjoerg		    }
83424139Sjoerg		}
83524139Sjoerg	    }
83624139Sjoerg	}
83724139Sjoerg	last_hi = hi;
83824139Sjoerg
83924139Sjoerg	/* move the cursor to a pleasant place */
84024139Sjoerg	Move_to(x_idlecursor, y_idlecursor);
84124139Sjoerg	lastline = y_idlecursor;
84224139Sjoerg    }
84324139Sjoerg    else
84424139Sjoerg    {
84524139Sjoerg	/* separate this display from the next with some vertical room */
84624139Sjoerg	fputs("\n\n", stdout);
84724139Sjoerg    }
84824139Sjoerg}
84924139Sjoerg
85024139Sjoergdisplay_header(t)
85124139Sjoerg
85224139Sjoergint t;
85324139Sjoerg
85424139Sjoerg{
85524139Sjoerg    if (t)
85624139Sjoerg    {
85724139Sjoerg	header_status = ON;
85824139Sjoerg    }
85924139Sjoerg    else if (header_status == ON)
86024139Sjoerg    {
86124139Sjoerg	header_status = ERASE;
86224139Sjoerg    }
86324139Sjoerg}
86424139Sjoerg
86524139Sjoerg/*VARARGS2*/
86624139Sjoergnew_message(type, msgfmt, a1, a2, a3)
86724139Sjoerg
86824139Sjoergint type;
86924139Sjoergchar *msgfmt;
87024139Sjoergcaddr_t a1, a2, a3;
87124139Sjoerg
87224139Sjoerg{
87324139Sjoerg    register int i;
87424139Sjoerg
87524139Sjoerg    /* first, format the message */
87666641Simp    (void) snprintf(next_msg, sizeof(next_msg), msgfmt, a1, a2, a3);
87724139Sjoerg
87824139Sjoerg    if (msglen > 0)
87924139Sjoerg    {
88024139Sjoerg	/* message there already -- can we clear it? */
88124139Sjoerg	if (!overstrike)
88224139Sjoerg	{
88324139Sjoerg	    /* yes -- write it and clear to end */
88424139Sjoerg	    i = strlen(next_msg);
88524139Sjoerg	    if ((type & MT_delayed) == 0)
88624139Sjoerg	    {
88724139Sjoerg		type & MT_standout ? standout(next_msg) :
88824139Sjoerg		                     fputs(next_msg, stdout);
88924139Sjoerg		(void) clear_eol(msglen - i);
89024139Sjoerg		msglen = i;
89124139Sjoerg		next_msg[0] = '\0';
89224139Sjoerg	    }
89324139Sjoerg	}
89424139Sjoerg    }
89524139Sjoerg    else
89624139Sjoerg    {
89724139Sjoerg	if ((type & MT_delayed) == 0)
89824139Sjoerg	{
89924139Sjoerg	    type & MT_standout ? standout(next_msg) : fputs(next_msg, stdout);
90024139Sjoerg	    msglen = strlen(next_msg);
90124139Sjoerg	    next_msg[0] = '\0';
90224139Sjoerg	}
90324139Sjoerg    }
90424139Sjoerg}
90524139Sjoerg
90624139Sjoergclear_message()
90724139Sjoerg
90824139Sjoerg{
90924139Sjoerg    if (clear_eol(msglen) == 1)
91024139Sjoerg    {
91124139Sjoerg	putchar('\r');
91224139Sjoerg    }
91324139Sjoerg}
91424139Sjoerg
91524139Sjoergreadline(buffer, size, numeric)
91624139Sjoerg
91724139Sjoergchar *buffer;
91824139Sjoergint  size;
91924139Sjoergint  numeric;
92024139Sjoerg
92124139Sjoerg{
92224139Sjoerg    register char *ptr = buffer;
92324139Sjoerg    register char ch;
92424139Sjoerg    register char cnt = 0;
92524139Sjoerg    register char maxcnt = 0;
92624139Sjoerg
92724139Sjoerg    /* allow room for null terminator */
92824139Sjoerg    size -= 1;
92924139Sjoerg
93024139Sjoerg    /* read loop */
93124139Sjoerg    while ((fflush(stdout), read(0, ptr, 1) > 0))
93224139Sjoerg    {
93324139Sjoerg	/* newline means we are done */
93424142Sjoerg	if ((ch = *ptr) == '\n' || ch == '\r')
93524139Sjoerg	{
93624139Sjoerg	    break;
93724139Sjoerg	}
93824139Sjoerg
93924139Sjoerg	/* handle special editing characters */
94024139Sjoerg	if (ch == ch_kill)
94124139Sjoerg	{
94224139Sjoerg	    /* kill line -- account for overstriking */
94324139Sjoerg	    if (overstrike)
94424139Sjoerg	    {
94524139Sjoerg		msglen += maxcnt;
94624139Sjoerg	    }
94724139Sjoerg
94824139Sjoerg	    /* return null string */
94924139Sjoerg	    *buffer = '\0';
95024139Sjoerg	    putchar('\r');
95124139Sjoerg	    return(-1);
95224139Sjoerg	}
95324139Sjoerg	else if (ch == ch_erase)
95424139Sjoerg	{
95524139Sjoerg	    /* erase previous character */
95624139Sjoerg	    if (cnt <= 0)
95724139Sjoerg	    {
95824139Sjoerg		/* none to erase! */
95924139Sjoerg		putchar('\7');
96024139Sjoerg	    }
96124139Sjoerg	    else
96224139Sjoerg	    {
96324139Sjoerg		fputs("\b \b", stdout);
96424139Sjoerg		ptr--;
96524139Sjoerg		cnt--;
96624139Sjoerg	    }
96724139Sjoerg	}
96824139Sjoerg	/* check for character validity and buffer overflow */
96924139Sjoerg	else if (cnt == size || (numeric && !isdigit(ch)) ||
97024139Sjoerg		!isprint(ch))
97124139Sjoerg	{
97224139Sjoerg	    /* not legal */
97324139Sjoerg	    putchar('\7');
97424139Sjoerg	}
97524139Sjoerg	else
97624139Sjoerg	{
97724139Sjoerg	    /* echo it and store it in the buffer */
97824139Sjoerg	    putchar(ch);
97924139Sjoerg	    ptr++;
98024139Sjoerg	    cnt++;
98124139Sjoerg	    if (cnt > maxcnt)
98224139Sjoerg	    {
98324139Sjoerg		maxcnt = cnt;
98424139Sjoerg	    }
98524139Sjoerg	}
98624139Sjoerg    }
98724139Sjoerg
98824139Sjoerg    /* all done -- null terminate the string */
98924139Sjoerg    *ptr = '\0';
99024139Sjoerg
99124139Sjoerg    /* account for the extra characters in the message area */
99224139Sjoerg    /* (if terminal overstrikes, remember the furthest they went) */
99324139Sjoerg    msglen += overstrike ? maxcnt : cnt;
99424139Sjoerg
99524139Sjoerg    /* return either inputted number or string length */
99624139Sjoerg    putchar('\r');
99724139Sjoerg    return(cnt == 0 ? -1 : numeric ? atoi(buffer) : cnt);
99824139Sjoerg}
99924139Sjoerg
100024139Sjoerg/* internal support routines */
100124139Sjoerg
100224139Sjoergstatic int string_count(pp)
100324139Sjoerg
100424139Sjoergregister char **pp;
100524139Sjoerg
100624139Sjoerg{
100724139Sjoerg    register int cnt;
100824139Sjoerg
100924139Sjoerg    cnt = 0;
101024139Sjoerg    while (*pp++ != NULL)
101124139Sjoerg    {
101224139Sjoerg	cnt++;
101324139Sjoerg    }
101424139Sjoerg    return(cnt);
101524139Sjoerg}
101624139Sjoerg
101724139Sjoergstatic void summary_format(str, numbers, names)
101824139Sjoerg
101924139Sjoergchar *str;
102024139Sjoergint *numbers;
102124139Sjoergregister char **names;
102224139Sjoerg
102324139Sjoerg{
102424139Sjoerg    register char *p;
102524139Sjoerg    register int num;
102624139Sjoerg    register char *thisname;
102724139Sjoerg    register int useM = No;
102824139Sjoerg
102924139Sjoerg    /* format each number followed by its string */
103024139Sjoerg    p = str;
103124139Sjoerg    while ((thisname = *names++) != NULL)
103224139Sjoerg    {
103324139Sjoerg	/* get the number to format */
103424139Sjoerg	num = *numbers++;
103524139Sjoerg
103624139Sjoerg	/* display only non-zero numbers */
103724139Sjoerg	if (num > 0)
103824139Sjoerg	{
103924139Sjoerg	    /* is this number in kilobytes? */
104024139Sjoerg	    if (thisname[0] == 'K')
104124139Sjoerg	    {
104224139Sjoerg		/* yes: format it as a memory value */
104324139Sjoerg		p = strecpy(p, format_k(num));
104424139Sjoerg
104524139Sjoerg		/* skip over the K, since it was included by format_k */
104624139Sjoerg		p = strecpy(p, thisname+1);
104724139Sjoerg	    }
104824139Sjoerg	    else
104924139Sjoerg	    {
105024139Sjoerg		p = strecpy(p, itoa(num));
105124139Sjoerg		p = strecpy(p, thisname);
105224139Sjoerg	    }
105324139Sjoerg	}
105424139Sjoerg
105524139Sjoerg	/* ignore negative numbers, but display corresponding string */
105624139Sjoerg	else if (num < 0)
105724139Sjoerg	{
105824139Sjoerg	    p = strecpy(p, thisname);
105924139Sjoerg	}
106024139Sjoerg    }
106124139Sjoerg
106224139Sjoerg    /* if the last two characters in the string are ", ", delete them */
106324139Sjoerg    p -= 2;
106424139Sjoerg    if (p >= str && p[0] == ',' && p[1] == ' ')
106524139Sjoerg    {
106624139Sjoerg	*p = '\0';
106724139Sjoerg    }
106824139Sjoerg}
106924139Sjoerg
107024139Sjoergstatic void line_update(old, new, start, line)
107124139Sjoerg
107224139Sjoergregister char *old;
107324139Sjoergregister char *new;
107424139Sjoergint start;
107524139Sjoergint line;
107624139Sjoerg
107724139Sjoerg{
107824139Sjoerg    register int ch;
107924139Sjoerg    register int diff;
108024139Sjoerg    register int newcol = start + 1;
108124139Sjoerg    register int lastcol = start;
108224139Sjoerg    char cursor_on_line = No;
108324139Sjoerg    char *current;
108424139Sjoerg
108524139Sjoerg    /* compare the two strings and only rewrite what has changed */
108624139Sjoerg    current = old;
108724139Sjoerg#ifdef DEBUG
108824139Sjoerg    fprintf(debug, "line_update, starting at %d\n", start);
108924139Sjoerg    fputs(old, debug);
109024139Sjoerg    fputc('\n', debug);
109124139Sjoerg    fputs(new, debug);
109224139Sjoerg    fputs("\n-\n", debug);
109324139Sjoerg#endif
109424139Sjoerg
109524139Sjoerg    /* start things off on the right foot		    */
109624139Sjoerg    /* this is to make sure the invariants get set up right */
109724139Sjoerg    if ((ch = *new++) != *old)
109824139Sjoerg    {
109924139Sjoerg	if (line - lastline == 1 && start == 0)
110024139Sjoerg	{
110124139Sjoerg	    putchar('\n');
110224139Sjoerg	}
110324139Sjoerg	else
110424139Sjoerg	{
110524139Sjoerg	    Move_to(start, line);
110624139Sjoerg	}
110724139Sjoerg	cursor_on_line = Yes;
110824139Sjoerg	putchar(ch);
110924139Sjoerg	*old = ch;
111024139Sjoerg	lastcol = 1;
111124139Sjoerg    }
111224139Sjoerg    old++;
111324139Sjoerg
111424139Sjoerg    /*
111524139Sjoerg     *  main loop -- check each character.  If the old and new aren't the
111624139Sjoerg     *	same, then update the display.  When the distance from the
111724139Sjoerg     *	current cursor position to the new change is small enough,
111824139Sjoerg     *	the characters that belong there are written to move the
111924139Sjoerg     *	cursor over.
112024139Sjoerg     *
112124139Sjoerg     *	Invariants:
112224139Sjoerg     *	    lastcol is the column where the cursor currently is sitting
112324139Sjoerg     *		(always one beyond the end of the last mismatch).
112424139Sjoerg     */
112524139Sjoerg    do		/* yes, a do...while */
112624139Sjoerg    {
112724139Sjoerg	if ((ch = *new++) != *old)
112824139Sjoerg	{
112924139Sjoerg	    /* new character is different from old	  */
113024139Sjoerg	    /* make sure the cursor is on top of this character */
113124139Sjoerg	    diff = newcol - lastcol;
113224139Sjoerg	    if (diff > 0)
113324139Sjoerg	    {
113424139Sjoerg		/* some motion is required--figure out which is shorter */
113524139Sjoerg		if (diff < 6 && cursor_on_line)
113624139Sjoerg		{
113724139Sjoerg		    /* overwrite old stuff--get it out of the old buffer */
113824139Sjoerg		    printf("%.*s", diff, &current[lastcol-start]);
113924139Sjoerg		}
114024139Sjoerg		else
114124139Sjoerg		{
114224139Sjoerg		    /* use cursor addressing */
114324139Sjoerg		    Move_to(newcol, line);
114424139Sjoerg		    cursor_on_line = Yes;
114524139Sjoerg		}
114624139Sjoerg		/* remember where the cursor is */
114724139Sjoerg		lastcol = newcol + 1;
114824139Sjoerg	    }
114924139Sjoerg	    else
115024139Sjoerg	    {
115124139Sjoerg		/* already there, update position */
115224139Sjoerg		lastcol++;
115324139Sjoerg	    }
115424139Sjoerg
115524139Sjoerg	    /* write what we need to */
115624139Sjoerg	    if (ch == '\0')
115724139Sjoerg	    {
115824139Sjoerg		/* at the end--terminate with a clear-to-end-of-line */
115924139Sjoerg		(void) clear_eol(strlen(old));
116024139Sjoerg	    }
116124139Sjoerg	    else
116224139Sjoerg	    {
116324139Sjoerg		/* write the new character */
116424139Sjoerg		putchar(ch);
116524139Sjoerg	    }
116624139Sjoerg	    /* put the new character in the screen buffer */
116724139Sjoerg	    *old = ch;
116824139Sjoerg	}
116924139Sjoerg
117024139Sjoerg	/* update working column and screen buffer pointer */
117124139Sjoerg	newcol++;
117224139Sjoerg	old++;
117324139Sjoerg
117424139Sjoerg    } while (ch != '\0');
117524139Sjoerg
117624139Sjoerg    /* zero out the rest of the line buffer -- MUST BE DONE! */
117724139Sjoerg    diff = display_width - newcol;
117824139Sjoerg    if (diff > 0)
117924139Sjoerg    {
118024139Sjoerg	memzero(old, diff);
118124139Sjoerg    }
118224139Sjoerg
118324139Sjoerg    /* remember where the current line is */
118424139Sjoerg    if (cursor_on_line)
118524139Sjoerg    {
118624139Sjoerg	lastline = line;
118724139Sjoerg    }
118824139Sjoerg}
118924139Sjoerg
119024139Sjoerg/*
119124139Sjoerg *  printable(str) - make the string pointed to by "str" into one that is
119224139Sjoerg *	printable (i.e.: all ascii), by converting all non-printable
119324139Sjoerg *	characters into '?'.  Replacements are done in place and a pointer
119424139Sjoerg *	to the original buffer is returned.
119524139Sjoerg */
119624139Sjoerg
119724139Sjoergchar *printable(str)
119824139Sjoerg
119924139Sjoergchar *str;
120024139Sjoerg
120124139Sjoerg{
120224139Sjoerg    register char *ptr;
120324139Sjoerg    register char ch;
120424139Sjoerg
120524139Sjoerg    ptr = str;
120624139Sjoerg    while ((ch = *ptr) != '\0')
120724139Sjoerg    {
120824139Sjoerg	if (!isprint(ch))
120924139Sjoerg	{
121024139Sjoerg	    *ptr = '?';
121124139Sjoerg	}
121224139Sjoerg	ptr++;
121324139Sjoerg    }
121424139Sjoerg    return(str);
121524139Sjoerg}
121642447Sobrien
121742447Sobrieni_uptime(bt, tod)
121842447Sobrien
121942447Sobrienstruct timeval* bt;
122042447Sobrientime_t *tod;
122142447Sobrien
122242447Sobrien{
122342447Sobrien    time_t uptime;
122442447Sobrien    int days, hrs, mins, secs;
122542447Sobrien
122642447Sobrien    if (bt->tv_sec != -1) {
122742447Sobrien	uptime = *tod - bt->tv_sec;
122842447Sobrien	uptime += 30;
122942447Sobrien	days = uptime / 86400;
123042447Sobrien	uptime %= 86400;
123142447Sobrien	hrs = uptime / 3600;
123242447Sobrien	uptime %= 3600;
123342447Sobrien	mins = uptime / 60;
123442447Sobrien	secs = uptime % 60;
123542447Sobrien
123642447Sobrien	/*
123742447Sobrien	 *  Display the uptime.
123842447Sobrien	 */
123942447Sobrien
124042447Sobrien	if (smart_terminal)
124142447Sobrien	{
124242447Sobrien	    Move_to((screen_width - 24) - (days > 9 ? 1 : 0), 0);
124342447Sobrien	}
124442447Sobrien	else
124542447Sobrien	{
124642447Sobrien	    fputs(" ", stdout);
124742447Sobrien	}
124842447Sobrien	printf(" up %d+%02d:%02d:%02d", days, hrs, mins, secs);
124942447Sobrien    }
125042447Sobrien}
1251