display.c revision 41943
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
1024139Sjoerg */
1124139Sjoerg
1224139Sjoerg/*
1324139Sjoerg *  This file contains the routines that display information on the screen.
1424139Sjoerg *  Each section of the screen has two routines:  one for initially writing
1524139Sjoerg *  all constant and dynamic text, and one for only updating the text that
1624139Sjoerg *  changes.  The prefix "i_" is used on all the "initial" routines and the
1724139Sjoerg *  prefix "u_" is used for all the "updating" routines.
1824139Sjoerg *
1924139Sjoerg *  ASSUMPTIONS:
2024139Sjoerg *        None of the "i_" routines use any of the termcap capabilities.
2124139Sjoerg *        In this way, those routines can be safely used on terminals that
2224139Sjoerg *        have minimal (or nonexistant) terminal capabilities.
2324139Sjoerg *
2424139Sjoerg *        The routines are called in this order:  *_loadave, i_timeofday,
2524139Sjoerg *        *_procstates, *_cpustates, *_memory, *_message, *_header,
2624139Sjoerg *        *_process, u_endscreen.
2724139Sjoerg */
2824139Sjoerg
2924139Sjoerg#include "os.h"
3024139Sjoerg#include <ctype.h>
3124139Sjoerg#include <time.h>
3241943Sobrien#include <sys/time.h>
3341943Sobrien#include <sys/types.h>
3441943Sobrien#include <sys/sysctl.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
10524139Sjoerg    /* we don't want more than MAX_COLS columns, since the machine-dependent
10624139Sjoerg       modules make static allocations based on MAX_COLS and we don't want
10724139Sjoerg       to run off the end of their buffers */
10824139Sjoerg    display_width = screen_width;
10924139Sjoerg    if (display_width >= MAX_COLS)
11024139Sjoerg    {
11124139Sjoerg	display_width = MAX_COLS - 1;
11224139Sjoerg    }
11324139Sjoerg
11424139Sjoerg    /* now, allocate space for the screen buffer */
11524139Sjoerg    screenbuf = (char *)malloc(lines * display_width);
11624139Sjoerg    if (screenbuf == (char *)NULL)
11724139Sjoerg    {
11824139Sjoerg	/* oops! */
11924139Sjoerg	return(-1);
12024139Sjoerg    }
12124139Sjoerg
12224139Sjoerg    /* return number of lines available */
12324139Sjoerg    /* for dumb terminals, pretend like we can show any amount */
12424139Sjoerg    return(smart_terminal ? lines : Largest);
12524139Sjoerg}
12624139Sjoerg
12724139Sjoergint display_init(statics)
12824139Sjoerg
12924139Sjoergstruct statics *statics;
13024139Sjoerg
13124139Sjoerg{
13224139Sjoerg    register int lines;
13324139Sjoerg    register char **pp;
13424139Sjoerg    register int *ip;
13524139Sjoerg    register int i;
13624139Sjoerg
13724139Sjoerg    /* call resize to do the dirty work */
13824139Sjoerg    lines = display_resize();
13924139Sjoerg
14024139Sjoerg    /* only do the rest if we need to */
14124139Sjoerg    if (lines > -1)
14224139Sjoerg    {
14324139Sjoerg	/* save pointers and allocate space for names */
14424139Sjoerg	procstate_names = statics->procstate_names;
14524139Sjoerg	num_procstates = string_count(procstate_names);
14624139Sjoerg	lprocstates = (int *)malloc(num_procstates * sizeof(int));
14724139Sjoerg
14824139Sjoerg	cpustate_names = statics->cpustate_names;
14924142Sjoerg
15024142Sjoerg	swap_names = statics->swap_names;
15124142Sjoerg	num_swap = string_count(swap_names);
15224142Sjoerg	lswap = (int *)malloc(num_swap * sizeof(int));
15324139Sjoerg	num_cpustates = string_count(cpustate_names);
15424139Sjoerg	lcpustates = (int *)malloc(num_cpustates * sizeof(int));
15524139Sjoerg	cpustate_columns = (int *)malloc(num_cpustates * sizeof(int));
15624139Sjoerg
15724139Sjoerg	memory_names = statics->memory_names;
15824139Sjoerg	num_memory = string_count(memory_names);
15924139Sjoerg	lmemory = (int *)malloc(num_memory * sizeof(int));
16024139Sjoerg
16124139Sjoerg	/* calculate starting columns where needed */
16224139Sjoerg	cpustate_total_length = 0;
16324139Sjoerg	pp = cpustate_names;
16424139Sjoerg	ip = cpustate_columns;
16524139Sjoerg	while (*pp != NULL)
16624139Sjoerg	{
16724139Sjoerg	    if ((i = strlen(*pp++)) > 0)
16824139Sjoerg	    {
16924139Sjoerg		*ip++ = cpustate_total_length;
17024139Sjoerg		cpustate_total_length += i + 8;
17124139Sjoerg	    }
17224139Sjoerg	}
17324139Sjoerg    }
17424139Sjoerg
17524139Sjoerg    /* return number of lines available */
17624139Sjoerg    return(lines);
17724139Sjoerg}
17824139Sjoerg
17924139Sjoergi_loadave(mpid, avenrun)
18024139Sjoerg
18124139Sjoergint mpid;
18224139Sjoergdouble *avenrun;
18324139Sjoerg
18424139Sjoerg{
18524139Sjoerg    register int i;
18624139Sjoerg
18724139Sjoerg    /* i_loadave also clears the screen, since it is first */
18824139Sjoerg    clear();
18924139Sjoerg
19024139Sjoerg    /* mpid == -1 implies this system doesn't have an _mpid */
19124139Sjoerg    if (mpid != -1)
19224139Sjoerg    {
19324139Sjoerg	printf("last pid: %5d;  ", mpid);
19424139Sjoerg    }
19524139Sjoerg
19624139Sjoerg    printf("load averages");
19724139Sjoerg
19824139Sjoerg    for (i = 0; i < 3; i++)
19924139Sjoerg    {
20024139Sjoerg	printf("%c %5.2f",
20124139Sjoerg	    i == 0 ? ':' : ',',
20224139Sjoerg	    avenrun[i]);
20324139Sjoerg    }
20424139Sjoerg    lmpid = mpid;
20524139Sjoerg}
20624139Sjoerg
20724139Sjoergu_loadave(mpid, avenrun)
20824139Sjoerg
20924139Sjoergint mpid;
21024139Sjoergdouble *avenrun;
21124139Sjoerg
21224139Sjoerg{
21324139Sjoerg    register int i;
21424139Sjoerg
21524139Sjoerg    if (mpid != -1)
21624139Sjoerg    {
21724139Sjoerg	/* change screen only when value has really changed */
21824139Sjoerg	if (mpid != lmpid)
21924139Sjoerg	{
22024139Sjoerg	    Move_to(x_lastpid, y_lastpid);
22124139Sjoerg	    printf("%5d", mpid);
22224139Sjoerg	    lmpid = mpid;
22324139Sjoerg	}
22424139Sjoerg
22524139Sjoerg	/* i remembers x coordinate to move to */
22624139Sjoerg	i = x_loadave;
22724139Sjoerg    }
22824139Sjoerg    else
22924139Sjoerg    {
23024139Sjoerg	i = x_loadave_nompid;
23124139Sjoerg    }
23224139Sjoerg
23324139Sjoerg    /* move into position for load averages */
23424139Sjoerg    Move_to(i, y_loadave);
23524139Sjoerg
23624139Sjoerg    /* display new load averages */
23724139Sjoerg    /* we should optimize this and only display changes */
23824139Sjoerg    for (i = 0; i < 3; i++)
23924139Sjoerg    {
24024139Sjoerg	printf("%s%5.2f",
24124139Sjoerg	    i == 0 ? "" : ", ",
24224139Sjoerg	    avenrun[i]);
24324139Sjoerg    }
24424139Sjoerg}
24524139Sjoerg
24641943Sobrienstruct timeval boottime;
24741943Sobrientime_t now;
24841943Sobrientime_t uptime;
24941943Sobrien
25024139Sjoergi_timeofday(tod)
25124139Sjoerg
25224139Sjoergtime_t *tod;
25324139Sjoerg
25424139Sjoerg{
25541943Sobrien       int days, hrs, i, mins, secs;
25641943Sobrien       int mib[2];
25741943Sobrien       size_t size;
25841943Sobrien
25941943Sobrien       (void)time(&now);
26041943Sobrien
26141943Sobrien        /*
26241943Sobrien         * Print how long system has been up.
26341943Sobrien         * (Found by looking getting "boottime" from the kernel)
26441943Sobrien         */
26541943Sobrien        mib[0] = CTL_KERN;
26641943Sobrien        mib[1] = KERN_BOOTTIME;
26741943Sobrien        size = sizeof(boottime);
26841943Sobrien        if (sysctl(mib, 2, &boottime, &size, NULL, 0) != -1 &&
26941943Sobrien            boottime.tv_sec != 0) {
27041943Sobrien                uptime = now - boottime.tv_sec;
27141943Sobrien                uptime += 30;
27241943Sobrien                days = uptime / 86400;
27341943Sobrien                uptime %= 86400;
27441943Sobrien                hrs = uptime / 3600;
27541943Sobrien                uptime %= 3600;
27641943Sobrien                mins = uptime / 60;
27741943Sobrien                secs = uptime % 60;
27841943Sobrien
27941943Sobrien               if (smart_terminal)
28041943Sobrien               {
28141943Sobrien                   Move_to((screen_width - 24) - (days > 9 ? 1 : 0), 0);
28241943Sobrien               }
28341943Sobrien               else
28441943Sobrien               {
28541943Sobrien                   fputs(" ", stdout);
28641943Sobrien               }
28741943Sobrien
28841943Sobrien               printf(" up %d+%02d:%02d:%02d", days, hrs, mins, secs);
28941943Sobrien        }
29041943Sobrien
29124139Sjoerg    /*
29224139Sjoerg     *  Display the current time.
29324139Sjoerg     *  "ctime" always returns a string that looks like this:
29424139Sjoerg     *
29524139Sjoerg     *	Sun Sep 16 01:03:52 1973
29624139Sjoerg     *      012345678901234567890123
29724139Sjoerg     *	          1         2
29824139Sjoerg     *
29924139Sjoerg     *  We want indices 11 thru 18 (length 8).
30024139Sjoerg     */
30124139Sjoerg
30224139Sjoerg    if (smart_terminal)
30324139Sjoerg    {
30424139Sjoerg	Move_to(screen_width - 8, 0);
30524139Sjoerg    }
30624139Sjoerg    else
30724139Sjoerg    {
30824139Sjoerg	fputs("    ", stdout);
30924139Sjoerg    }
31024139Sjoerg#ifdef DEBUG
31124139Sjoerg    {
31224139Sjoerg	char *foo;
31324139Sjoerg	foo = ctime(tod);
31424139Sjoerg	fputs(foo, stdout);
31524139Sjoerg    }
31624139Sjoerg#endif
31724139Sjoerg    printf("%-8.8s\n", &(ctime(tod)[11]));
31824139Sjoerg    lastline = 1;
31924139Sjoerg}
32024139Sjoerg
32124139Sjoergstatic int ltotal = 0;
32224139Sjoergstatic char procstates_buffer[128];
32324139Sjoerg
32424139Sjoerg/*
32524139Sjoerg *  *_procstates(total, brkdn, names) - print the process summary line
32624139Sjoerg *
32724139Sjoerg *  Assumptions:  cursor is at the beginning of the line on entry
32824139Sjoerg *		  lastline is valid
32924139Sjoerg */
33024139Sjoerg
33124139Sjoergi_procstates(total, brkdn)
33224139Sjoerg
33324139Sjoergint total;
33424139Sjoergint *brkdn;
33524139Sjoerg
33624139Sjoerg{
33724139Sjoerg    register int i;
33824139Sjoerg
33924139Sjoerg    /* write current number of processes and remember the value */
34024139Sjoerg    printf("%d processes:", total);
34124139Sjoerg    ltotal = total;
34224139Sjoerg
34324139Sjoerg    /* put out enough spaces to get to column 15 */
34424139Sjoerg    i = digits(total);
34524139Sjoerg    while (i++ < 4)
34624139Sjoerg    {
34724139Sjoerg	putchar(' ');
34824139Sjoerg    }
34924139Sjoerg
35024139Sjoerg    /* format and print the process state summary */
35124139Sjoerg    summary_format(procstates_buffer, brkdn, procstate_names);
35224139Sjoerg    fputs(procstates_buffer, stdout);
35324139Sjoerg
35424139Sjoerg    /* save the numbers for next time */
35524139Sjoerg    memcpy(lprocstates, brkdn, num_procstates * sizeof(int));
35624139Sjoerg}
35724139Sjoerg
35824139Sjoergu_procstates(total, brkdn)
35924139Sjoerg
36024139Sjoergint total;
36124139Sjoergint *brkdn;
36224139Sjoerg
36324139Sjoerg{
36424139Sjoerg    static char new[128];
36524139Sjoerg    register int i;
36624139Sjoerg
36724139Sjoerg    /* update number of processes only if it has changed */
36824139Sjoerg    if (ltotal != total)
36924139Sjoerg    {
37024139Sjoerg	/* move and overwrite */
37124139Sjoerg#if (x_procstate == 0)
37224139Sjoerg	Move_to(x_procstate, y_procstate);
37324139Sjoerg#else
37424139Sjoerg	/* cursor is already there...no motion needed */
37524139Sjoerg	/* assert(lastline == 1); */
37624139Sjoerg#endif
37724139Sjoerg	printf("%d", total);
37824139Sjoerg
37924139Sjoerg	/* if number of digits differs, rewrite the label */
38024139Sjoerg	if (digits(total) != digits(ltotal))
38124139Sjoerg	{
38224139Sjoerg	    fputs(" processes:", stdout);
38324139Sjoerg	    /* put out enough spaces to get to column 15 */
38424139Sjoerg	    i = digits(total);
38524139Sjoerg	    while (i++ < 4)
38624139Sjoerg	    {
38724139Sjoerg		putchar(' ');
38824139Sjoerg	    }
38924139Sjoerg	    /* cursor may end up right where we want it!!! */
39024139Sjoerg	}
39124139Sjoerg
39224139Sjoerg	/* save new total */
39324139Sjoerg	ltotal = total;
39424139Sjoerg    }
39524139Sjoerg
39624139Sjoerg    /* see if any of the state numbers has changed */
39724139Sjoerg    if (memcmp(lprocstates, brkdn, num_procstates * sizeof(int)) != 0)
39824139Sjoerg    {
39924139Sjoerg	/* format and update the line */
40024139Sjoerg	summary_format(new, brkdn, procstate_names);
40124139Sjoerg	line_update(procstates_buffer, new, x_brkdn, y_brkdn);
40224139Sjoerg	memcpy(lprocstates, brkdn, num_procstates * sizeof(int));
40324139Sjoerg    }
40424139Sjoerg}
40524139Sjoerg
40624139Sjoerg/*
40724139Sjoerg *  *_cpustates(states, names) - print the cpu state percentages
40824139Sjoerg *
40924139Sjoerg *  Assumptions:  cursor is on the PREVIOUS line
41024139Sjoerg */
41124139Sjoerg
41224139Sjoergstatic int cpustates_column;
41324139Sjoerg
41424139Sjoerg/* cpustates_tag() calculates the correct tag to use to label the line */
41524139Sjoerg
41624139Sjoergchar *cpustates_tag()
41724139Sjoerg
41824139Sjoerg{
41924139Sjoerg    register char *use;
42024139Sjoerg
42124139Sjoerg    static char *short_tag = "CPU: ";
42224139Sjoerg    static char *long_tag = "CPU states: ";
42324139Sjoerg
42424139Sjoerg    /* if length + strlen(long_tag) >= screen_width, then we have to
42524139Sjoerg       use the shorter tag (we subtract 2 to account for ": ") */
42624139Sjoerg    if (cpustate_total_length + (int)strlen(long_tag) - 2 >= screen_width)
42724139Sjoerg    {
42824139Sjoerg	use = short_tag;
42924139Sjoerg    }
43024139Sjoerg    else
43124139Sjoerg    {
43224139Sjoerg	use = long_tag;
43324139Sjoerg    }
43424139Sjoerg
43524139Sjoerg    /* set cpustates_column accordingly then return result */
43624139Sjoerg    cpustates_column = strlen(use);
43724139Sjoerg    return(use);
43824139Sjoerg}
43924139Sjoerg
44024139Sjoergi_cpustates(states)
44124139Sjoerg
44224139Sjoergregister int *states;
44324139Sjoerg
44424139Sjoerg{
44524139Sjoerg    register int i = 0;
44624139Sjoerg    register int value;
44724139Sjoerg    register char **names = cpustate_names;
44824139Sjoerg    register char *thisname;
44924139Sjoerg
45024139Sjoerg    /* print tag and bump lastline */
45124139Sjoerg    printf("\n%s", cpustates_tag());
45224139Sjoerg    lastline++;
45324139Sjoerg
45424139Sjoerg    /* now walk thru the names and print the line */
45524139Sjoerg    while ((thisname = *names++) != NULL)
45624139Sjoerg    {
45724139Sjoerg	if (*thisname != '\0')
45824139Sjoerg	{
45924139Sjoerg	    /* retrieve the value and remember it */
46024139Sjoerg	    value = *states++;
46124139Sjoerg
46224139Sjoerg	    /* if percentage is >= 1000, print it as 100% */
46324139Sjoerg	    printf((value >= 1000 ? "%s%4.0f%% %s" : "%s%4.1f%% %s"),
46424139Sjoerg		   i++ == 0 ? "" : ", ",
46524139Sjoerg		   ((float)value)/10.,
46624139Sjoerg		   thisname);
46724139Sjoerg	}
46824139Sjoerg    }
46924139Sjoerg
47024139Sjoerg    /* copy over values into "last" array */
47124139Sjoerg    memcpy(lcpustates, states, num_cpustates * sizeof(int));
47224139Sjoerg}
47324139Sjoerg
47424139Sjoergu_cpustates(states)
47524139Sjoerg
47624139Sjoergregister int *states;
47724139Sjoerg
47824139Sjoerg{
47924139Sjoerg    register int value;
48024139Sjoerg    register char **names = cpustate_names;
48124139Sjoerg    register char *thisname;
48224139Sjoerg    register int *lp;
48324139Sjoerg    register int *colp;
48424139Sjoerg
48524139Sjoerg    Move_to(cpustates_column, y_cpustates);
48624139Sjoerg    lastline = y_cpustates;
48724139Sjoerg    lp = lcpustates;
48824139Sjoerg    colp = cpustate_columns;
48924139Sjoerg
49024139Sjoerg    /* we could be much more optimal about this */
49124139Sjoerg    while ((thisname = *names++) != NULL)
49224139Sjoerg    {
49324139Sjoerg	if (*thisname != '\0')
49424139Sjoerg	{
49524139Sjoerg	    /* did the value change since last time? */
49624139Sjoerg	    if (*lp != *states)
49724139Sjoerg	    {
49824139Sjoerg		/* yes, move and change */
49924139Sjoerg		Move_to(cpustates_column + *colp, y_cpustates);
50024139Sjoerg		lastline = y_cpustates;
50124139Sjoerg
50224139Sjoerg		/* retrieve value and remember it */
50324139Sjoerg		value = *states;
50424139Sjoerg
50524139Sjoerg		/* if percentage is >= 1000, print it as 100% */
50624139Sjoerg		printf((value >= 1000 ? "%4.0f" : "%4.1f"),
50724139Sjoerg		       ((double)value)/10.);
50824139Sjoerg
50924139Sjoerg		/* remember it for next time */
51024139Sjoerg		*lp = *states;
51124139Sjoerg	    }
51224139Sjoerg	}
51324139Sjoerg
51424139Sjoerg	/* increment and move on */
51524139Sjoerg	lp++;
51624139Sjoerg	states++;
51724139Sjoerg	colp++;
51824139Sjoerg    }
51924139Sjoerg}
52024139Sjoerg
52124139Sjoergz_cpustates()
52224139Sjoerg
52324139Sjoerg{
52424139Sjoerg    register int i = 0;
52524139Sjoerg    register char **names = cpustate_names;
52624139Sjoerg    register char *thisname;
52724139Sjoerg    register int *lp;
52824139Sjoerg
52924139Sjoerg    /* show tag and bump lastline */
53024139Sjoerg    printf("\n%s", cpustates_tag());
53124139Sjoerg    lastline++;
53224139Sjoerg
53324139Sjoerg    while ((thisname = *names++) != NULL)
53424139Sjoerg    {
53524139Sjoerg	if (*thisname != '\0')
53624139Sjoerg	{
53724139Sjoerg	    printf("%s    %% %s", i++ == 0 ? "" : ", ", thisname);
53824139Sjoerg	}
53924139Sjoerg    }
54024139Sjoerg
54124139Sjoerg    /* fill the "last" array with all -1s, to insure correct updating */
54224139Sjoerg    lp = lcpustates;
54324139Sjoerg    i = num_cpustates;
54424139Sjoerg    while (--i >= 0)
54524139Sjoerg    {
54624139Sjoerg	*lp++ = -1;
54724139Sjoerg    }
54824139Sjoerg}
54924139Sjoerg
55024139Sjoerg/*
55124139Sjoerg *  *_memory(stats) - print "Memory: " followed by the memory summary string
55224139Sjoerg *
55324139Sjoerg *  Assumptions:  cursor is on "lastline"
55424139Sjoerg *                for i_memory ONLY: cursor is on the previous line
55524139Sjoerg */
55624139Sjoerg
55724139Sjoergchar memory_buffer[MAX_COLS];
55824139Sjoerg
55924139Sjoergi_memory(stats)
56024139Sjoerg
56124139Sjoergint *stats;
56224139Sjoerg
56324139Sjoerg{
56424142Sjoerg    fputs("\nMem: ", stdout);
56524139Sjoerg    lastline++;
56624139Sjoerg
56724139Sjoerg    /* format and print the memory summary */
56824139Sjoerg    summary_format(memory_buffer, stats, memory_names);
56924139Sjoerg    fputs(memory_buffer, stdout);
57024139Sjoerg}
57124139Sjoerg
57224139Sjoergu_memory(stats)
57324139Sjoerg
57424139Sjoergint *stats;
57524139Sjoerg
57624139Sjoerg{
57724139Sjoerg    static char new[MAX_COLS];
57824139Sjoerg
57924139Sjoerg    /* format the new line */
58024139Sjoerg    summary_format(new, stats, memory_names);
58124139Sjoerg    line_update(memory_buffer, new, x_mem, y_mem);
58224139Sjoerg}
58324139Sjoerg
58424139Sjoerg/*
58524142Sjoerg *  *_swap(stats) - print "Swap: " followed by the swap summary string
58624142Sjoerg *
58724142Sjoerg *  Assumptions:  cursor is on "lastline"
58824142Sjoerg *                for i_swap ONLY: cursor is on the previous line
58924142Sjoerg */
59024142Sjoerg
59124142Sjoergchar swap_buffer[MAX_COLS];
59224142Sjoerg
59324142Sjoergi_swap(stats)
59424142Sjoerg
59524142Sjoergint *stats;
59624142Sjoerg
59724142Sjoerg{
59824142Sjoerg    fputs("\nSwap: ", stdout);
59924142Sjoerg    lastline++;
60024142Sjoerg
60124142Sjoerg    /* format and print the swap summary */
60224142Sjoerg    summary_format(swap_buffer, stats, swap_names);
60324142Sjoerg    fputs(swap_buffer, stdout);
60424142Sjoerg}
60524142Sjoerg
60624142Sjoergu_swap(stats)
60724142Sjoerg
60824142Sjoergint *stats;
60924142Sjoerg
61024142Sjoerg{
61124142Sjoerg    static char new[MAX_COLS];
61224142Sjoerg
61324142Sjoerg    /* format the new line */
61424142Sjoerg    summary_format(new, stats, swap_names);
61524142Sjoerg    line_update(swap_buffer, new, x_swap, y_swap);
61624142Sjoerg}
61724142Sjoerg
61824142Sjoerg/*
61924139Sjoerg *  *_message() - print the next pending message line, or erase the one
62024139Sjoerg *                that is there.
62124139Sjoerg *
62224139Sjoerg *  Note that u_message is (currently) the same as i_message.
62324139Sjoerg *
62424139Sjoerg *  Assumptions:  lastline is consistent
62524139Sjoerg */
62624139Sjoerg
62724139Sjoerg/*
62824139Sjoerg *  i_message is funny because it gets its message asynchronously (with
62924139Sjoerg *	respect to screen updates).
63024139Sjoerg */
63124139Sjoerg
63224139Sjoergstatic char next_msg[MAX_COLS + 5];
63324139Sjoergstatic int msglen = 0;
63424139Sjoerg/* Invariant: msglen is always the length of the message currently displayed
63524139Sjoerg   on the screen (even when next_msg doesn't contain that message). */
63624139Sjoerg
63724139Sjoergi_message()
63824139Sjoerg
63924139Sjoerg{
64024139Sjoerg    while (lastline < y_message)
64124139Sjoerg    {
64224139Sjoerg	fputc('\n', stdout);
64324139Sjoerg	lastline++;
64424139Sjoerg    }
64524139Sjoerg    if (next_msg[0] != '\0')
64624139Sjoerg    {
64724139Sjoerg	standout(next_msg);
64824139Sjoerg	msglen = strlen(next_msg);
64924139Sjoerg	next_msg[0] = '\0';
65024139Sjoerg    }
65124139Sjoerg    else if (msglen > 0)
65224139Sjoerg    {
65324139Sjoerg	(void) clear_eol(msglen);
65424139Sjoerg	msglen = 0;
65524139Sjoerg    }
65624139Sjoerg}
65724139Sjoerg
65824139Sjoergu_message()
65924139Sjoerg
66024139Sjoerg{
66124139Sjoerg    i_message();
66224139Sjoerg}
66324139Sjoerg
66424139Sjoergstatic int header_length;
66524139Sjoerg
66624139Sjoerg/*
66724139Sjoerg *  *_header(text) - print the header for the process area
66824139Sjoerg *
66924139Sjoerg *  Assumptions:  cursor is on the previous line and lastline is consistent
67024139Sjoerg */
67124139Sjoerg
67224139Sjoergi_header(text)
67324139Sjoerg
67424139Sjoergchar *text;
67524139Sjoerg
67624139Sjoerg{
67724139Sjoerg    header_length = strlen(text);
67824139Sjoerg    if (header_status == ON)
67924139Sjoerg    {
68024139Sjoerg	putchar('\n');
68124139Sjoerg	fputs(text, stdout);
68224139Sjoerg	lastline++;
68324139Sjoerg    }
68424139Sjoerg    else if (header_status == ERASE)
68524139Sjoerg    {
68624139Sjoerg	header_status = OFF;
68724139Sjoerg    }
68824139Sjoerg}
68924139Sjoerg
69024139Sjoerg/*ARGSUSED*/
69124139Sjoergu_header(text)
69224139Sjoerg
69324139Sjoergchar *text;		/* ignored */
69424139Sjoerg
69524139Sjoerg{
69624139Sjoerg    if (header_status == ERASE)
69724139Sjoerg    {
69824139Sjoerg	putchar('\n');
69924139Sjoerg	lastline++;
70024139Sjoerg	clear_eol(header_length);
70124139Sjoerg	header_status = OFF;
70224139Sjoerg    }
70324139Sjoerg}
70424139Sjoerg
70524139Sjoerg/*
70624139Sjoerg *  *_process(line, thisline) - print one process line
70724139Sjoerg *
70824139Sjoerg *  Assumptions:  lastline is consistent
70924139Sjoerg */
71024139Sjoerg
71124139Sjoergi_process(line, thisline)
71224139Sjoerg
71324139Sjoergint line;
71424139Sjoergchar *thisline;
71524139Sjoerg
71624139Sjoerg{
71724139Sjoerg    register char *p;
71824139Sjoerg    register char *base;
71924139Sjoerg
72024139Sjoerg    /* make sure we are on the correct line */
72124139Sjoerg    while (lastline < y_procs + line)
72224139Sjoerg    {
72324139Sjoerg	putchar('\n');
72424139Sjoerg	lastline++;
72524139Sjoerg    }
72624139Sjoerg
72724139Sjoerg    /* truncate the line to conform to our current screen width */
72824139Sjoerg    thisline[display_width] = '\0';
72924139Sjoerg
73024139Sjoerg    /* write the line out */
73124139Sjoerg    fputs(thisline, stdout);
73224139Sjoerg
73324139Sjoerg    /* copy it in to our buffer */
73424139Sjoerg    base = smart_terminal ? screenbuf + lineindex(line) : screenbuf;
73524139Sjoerg    p = strecpy(base, thisline);
73624139Sjoerg
73724139Sjoerg    /* zero fill the rest of it */
73824139Sjoerg    memzero(p, display_width - (p - base));
73924139Sjoerg}
74024139Sjoerg
74124139Sjoergu_process(line, newline)
74224139Sjoerg
74324139Sjoergint line;
74424139Sjoergchar *newline;
74524139Sjoerg
74624139Sjoerg{
74724139Sjoerg    register char *optr;
74824139Sjoerg    register int screen_line = line + Header_lines;
74924139Sjoerg    register char *bufferline;
75024139Sjoerg
75124139Sjoerg    /* remember a pointer to the current line in the screen buffer */
75224139Sjoerg    bufferline = &screenbuf[lineindex(line)];
75324139Sjoerg
75424139Sjoerg    /* truncate the line to conform to our current screen width */
75524139Sjoerg    newline[display_width] = '\0';
75624139Sjoerg
75724139Sjoerg    /* is line higher than we went on the last display? */
75824139Sjoerg    if (line >= last_hi)
75924139Sjoerg    {
76024139Sjoerg	/* yes, just ignore screenbuf and write it out directly */
76124139Sjoerg	/* get positioned on the correct line */
76224139Sjoerg	if (screen_line - lastline == 1)
76324139Sjoerg	{
76424139Sjoerg	    putchar('\n');
76524139Sjoerg	    lastline++;
76624139Sjoerg	}
76724139Sjoerg	else
76824139Sjoerg	{
76924139Sjoerg	    Move_to(0, screen_line);
77024139Sjoerg	    lastline = screen_line;
77124139Sjoerg	}
77224139Sjoerg
77324139Sjoerg	/* now write the line */
77424139Sjoerg	fputs(newline, stdout);
77524139Sjoerg
77624139Sjoerg	/* copy it in to the buffer */
77724139Sjoerg	optr = strecpy(bufferline, newline);
77824139Sjoerg
77924139Sjoerg	/* zero fill the rest of it */
78024139Sjoerg	memzero(optr, display_width - (optr - bufferline));
78124139Sjoerg    }
78224139Sjoerg    else
78324139Sjoerg    {
78424139Sjoerg	line_update(bufferline, newline, 0, line + Header_lines);
78524139Sjoerg    }
78624139Sjoerg}
78724139Sjoerg
78824139Sjoergu_endscreen(hi)
78924139Sjoerg
79024139Sjoergregister int hi;
79124139Sjoerg
79224139Sjoerg{
79324139Sjoerg    register int screen_line = hi + Header_lines;
79424139Sjoerg    register int i;
79524139Sjoerg
79624139Sjoerg    if (smart_terminal)
79724139Sjoerg    {
79824139Sjoerg	if (hi < last_hi)
79924139Sjoerg	{
80024139Sjoerg	    /* need to blank the remainder of the screen */
80124139Sjoerg	    /* but only if there is any screen left below this line */
80224139Sjoerg	    if (lastline + 1 < screen_length)
80324139Sjoerg	    {
80424139Sjoerg		/* efficiently move to the end of currently displayed info */
80524139Sjoerg		if (screen_line - lastline < 5)
80624139Sjoerg		{
80724139Sjoerg		    while (lastline < screen_line)
80824139Sjoerg		    {
80924139Sjoerg			putchar('\n');
81024139Sjoerg			lastline++;
81124139Sjoerg		    }
81224139Sjoerg		}
81324139Sjoerg		else
81424139Sjoerg		{
81524139Sjoerg		    Move_to(0, screen_line);
81624139Sjoerg		    lastline = screen_line;
81724139Sjoerg		}
81824139Sjoerg
81924139Sjoerg		if (clear_to_end)
82024139Sjoerg		{
82124139Sjoerg		    /* we can do this the easy way */
82224139Sjoerg		    putcap(clear_to_end);
82324139Sjoerg		}
82424139Sjoerg		else
82524139Sjoerg		{
82624139Sjoerg		    /* use clear_eol on each line */
82724139Sjoerg		    i = hi;
82824139Sjoerg		    while ((void) clear_eol(strlen(&screenbuf[lineindex(i++)])), i < last_hi)
82924139Sjoerg		    {
83024139Sjoerg			putchar('\n');
83124139Sjoerg		    }
83224139Sjoerg		}
83324139Sjoerg	    }
83424139Sjoerg	}
83524139Sjoerg	last_hi = hi;
83624139Sjoerg
83724139Sjoerg	/* move the cursor to a pleasant place */
83824139Sjoerg	Move_to(x_idlecursor, y_idlecursor);
83924139Sjoerg	lastline = y_idlecursor;
84024139Sjoerg    }
84124139Sjoerg    else
84224139Sjoerg    {
84324139Sjoerg	/* separate this display from the next with some vertical room */
84424139Sjoerg	fputs("\n\n", stdout);
84524139Sjoerg    }
84624139Sjoerg}
84724139Sjoerg
84824139Sjoergdisplay_header(t)
84924139Sjoerg
85024139Sjoergint t;
85124139Sjoerg
85224139Sjoerg{
85324139Sjoerg    if (t)
85424139Sjoerg    {
85524139Sjoerg	header_status = ON;
85624139Sjoerg    }
85724139Sjoerg    else if (header_status == ON)
85824139Sjoerg    {
85924139Sjoerg	header_status = ERASE;
86024139Sjoerg    }
86124139Sjoerg}
86224139Sjoerg
86324139Sjoerg/*VARARGS2*/
86424139Sjoergnew_message(type, msgfmt, a1, a2, a3)
86524139Sjoerg
86624139Sjoergint type;
86724139Sjoergchar *msgfmt;
86824139Sjoergcaddr_t a1, a2, a3;
86924139Sjoerg
87024139Sjoerg{
87124139Sjoerg    register int i;
87224139Sjoerg
87324139Sjoerg    /* first, format the message */
87424139Sjoerg    (void) sprintf(next_msg, msgfmt, a1, a2, a3);
87524139Sjoerg
87624139Sjoerg    if (msglen > 0)
87724139Sjoerg    {
87824139Sjoerg	/* message there already -- can we clear it? */
87924139Sjoerg	if (!overstrike)
88024139Sjoerg	{
88124139Sjoerg	    /* yes -- write it and clear to end */
88224139Sjoerg	    i = strlen(next_msg);
88324139Sjoerg	    if ((type & MT_delayed) == 0)
88424139Sjoerg	    {
88524139Sjoerg		type & MT_standout ? standout(next_msg) :
88624139Sjoerg		                     fputs(next_msg, stdout);
88724139Sjoerg		(void) clear_eol(msglen - i);
88824139Sjoerg		msglen = i;
88924139Sjoerg		next_msg[0] = '\0';
89024139Sjoerg	    }
89124139Sjoerg	}
89224139Sjoerg    }
89324139Sjoerg    else
89424139Sjoerg    {
89524139Sjoerg	if ((type & MT_delayed) == 0)
89624139Sjoerg	{
89724139Sjoerg	    type & MT_standout ? standout(next_msg) : fputs(next_msg, stdout);
89824139Sjoerg	    msglen = strlen(next_msg);
89924139Sjoerg	    next_msg[0] = '\0';
90024139Sjoerg	}
90124139Sjoerg    }
90224139Sjoerg}
90324139Sjoerg
90424139Sjoergclear_message()
90524139Sjoerg
90624139Sjoerg{
90724139Sjoerg    if (clear_eol(msglen) == 1)
90824139Sjoerg    {
90924139Sjoerg	putchar('\r');
91024139Sjoerg    }
91124139Sjoerg}
91224139Sjoerg
91324139Sjoergreadline(buffer, size, numeric)
91424139Sjoerg
91524139Sjoergchar *buffer;
91624139Sjoergint  size;
91724139Sjoergint  numeric;
91824139Sjoerg
91924139Sjoerg{
92024139Sjoerg    register char *ptr = buffer;
92124139Sjoerg    register char ch;
92224139Sjoerg    register char cnt = 0;
92324139Sjoerg    register char maxcnt = 0;
92424139Sjoerg
92524139Sjoerg    /* allow room for null terminator */
92624139Sjoerg    size -= 1;
92724139Sjoerg
92824139Sjoerg    /* read loop */
92924139Sjoerg    while ((fflush(stdout), read(0, ptr, 1) > 0))
93024139Sjoerg    {
93124139Sjoerg	/* newline means we are done */
93224142Sjoerg	if ((ch = *ptr) == '\n' || ch == '\r')
93324139Sjoerg	{
93424139Sjoerg	    break;
93524139Sjoerg	}
93624139Sjoerg
93724139Sjoerg	/* handle special editing characters */
93824139Sjoerg	if (ch == ch_kill)
93924139Sjoerg	{
94024139Sjoerg	    /* kill line -- account for overstriking */
94124139Sjoerg	    if (overstrike)
94224139Sjoerg	    {
94324139Sjoerg		msglen += maxcnt;
94424139Sjoerg	    }
94524139Sjoerg
94624139Sjoerg	    /* return null string */
94724139Sjoerg	    *buffer = '\0';
94824139Sjoerg	    putchar('\r');
94924139Sjoerg	    return(-1);
95024139Sjoerg	}
95124139Sjoerg	else if (ch == ch_erase)
95224139Sjoerg	{
95324139Sjoerg	    /* erase previous character */
95424139Sjoerg	    if (cnt <= 0)
95524139Sjoerg	    {
95624139Sjoerg		/* none to erase! */
95724139Sjoerg		putchar('\7');
95824139Sjoerg	    }
95924139Sjoerg	    else
96024139Sjoerg	    {
96124139Sjoerg		fputs("\b \b", stdout);
96224139Sjoerg		ptr--;
96324139Sjoerg		cnt--;
96424139Sjoerg	    }
96524139Sjoerg	}
96624139Sjoerg	/* check for character validity and buffer overflow */
96724139Sjoerg	else if (cnt == size || (numeric && !isdigit(ch)) ||
96824139Sjoerg		!isprint(ch))
96924139Sjoerg	{
97024139Sjoerg	    /* not legal */
97124139Sjoerg	    putchar('\7');
97224139Sjoerg	}
97324139Sjoerg	else
97424139Sjoerg	{
97524139Sjoerg	    /* echo it and store it in the buffer */
97624139Sjoerg	    putchar(ch);
97724139Sjoerg	    ptr++;
97824139Sjoerg	    cnt++;
97924139Sjoerg	    if (cnt > maxcnt)
98024139Sjoerg	    {
98124139Sjoerg		maxcnt = cnt;
98224139Sjoerg	    }
98324139Sjoerg	}
98424139Sjoerg    }
98524139Sjoerg
98624139Sjoerg    /* all done -- null terminate the string */
98724139Sjoerg    *ptr = '\0';
98824139Sjoerg
98924139Sjoerg    /* account for the extra characters in the message area */
99024139Sjoerg    /* (if terminal overstrikes, remember the furthest they went) */
99124139Sjoerg    msglen += overstrike ? maxcnt : cnt;
99224139Sjoerg
99324139Sjoerg    /* return either inputted number or string length */
99424139Sjoerg    putchar('\r');
99524139Sjoerg    return(cnt == 0 ? -1 : numeric ? atoi(buffer) : cnt);
99624139Sjoerg}
99724139Sjoerg
99824139Sjoerg/* internal support routines */
99924139Sjoerg
100024139Sjoergstatic int string_count(pp)
100124139Sjoerg
100224139Sjoergregister char **pp;
100324139Sjoerg
100424139Sjoerg{
100524139Sjoerg    register int cnt;
100624139Sjoerg
100724139Sjoerg    cnt = 0;
100824139Sjoerg    while (*pp++ != NULL)
100924139Sjoerg    {
101024139Sjoerg	cnt++;
101124139Sjoerg    }
101224139Sjoerg    return(cnt);
101324139Sjoerg}
101424139Sjoerg
101524139Sjoergstatic void summary_format(str, numbers, names)
101624139Sjoerg
101724139Sjoergchar *str;
101824139Sjoergint *numbers;
101924139Sjoergregister char **names;
102024139Sjoerg
102124139Sjoerg{
102224139Sjoerg    register char *p;
102324139Sjoerg    register int num;
102424139Sjoerg    register char *thisname;
102524139Sjoerg    register int useM = No;
102624139Sjoerg
102724139Sjoerg    /* format each number followed by its string */
102824139Sjoerg    p = str;
102924139Sjoerg    while ((thisname = *names++) != NULL)
103024139Sjoerg    {
103124139Sjoerg	/* get the number to format */
103224139Sjoerg	num = *numbers++;
103324139Sjoerg
103424139Sjoerg	/* display only non-zero numbers */
103524139Sjoerg	if (num > 0)
103624139Sjoerg	{
103724139Sjoerg	    /* is this number in kilobytes? */
103824139Sjoerg	    if (thisname[0] == 'K')
103924139Sjoerg	    {
104024139Sjoerg		/* yes: format it as a memory value */
104124139Sjoerg		p = strecpy(p, format_k(num));
104224139Sjoerg
104324139Sjoerg		/* skip over the K, since it was included by format_k */
104424139Sjoerg		p = strecpy(p, thisname+1);
104524139Sjoerg	    }
104624139Sjoerg	    else
104724139Sjoerg	    {
104824139Sjoerg		p = strecpy(p, itoa(num));
104924139Sjoerg		p = strecpy(p, thisname);
105024139Sjoerg	    }
105124139Sjoerg	}
105224139Sjoerg
105324139Sjoerg	/* ignore negative numbers, but display corresponding string */
105424139Sjoerg	else if (num < 0)
105524139Sjoerg	{
105624139Sjoerg	    p = strecpy(p, thisname);
105724139Sjoerg	}
105824139Sjoerg    }
105924139Sjoerg
106024139Sjoerg    /* if the last two characters in the string are ", ", delete them */
106124139Sjoerg    p -= 2;
106224139Sjoerg    if (p >= str && p[0] == ',' && p[1] == ' ')
106324139Sjoerg    {
106424139Sjoerg	*p = '\0';
106524139Sjoerg    }
106624139Sjoerg}
106724139Sjoerg
106824139Sjoergstatic void line_update(old, new, start, line)
106924139Sjoerg
107024139Sjoergregister char *old;
107124139Sjoergregister char *new;
107224139Sjoergint start;
107324139Sjoergint line;
107424139Sjoerg
107524139Sjoerg{
107624139Sjoerg    register int ch;
107724139Sjoerg    register int diff;
107824139Sjoerg    register int newcol = start + 1;
107924139Sjoerg    register int lastcol = start;
108024139Sjoerg    char cursor_on_line = No;
108124139Sjoerg    char *current;
108224139Sjoerg
108324139Sjoerg    /* compare the two strings and only rewrite what has changed */
108424139Sjoerg    current = old;
108524139Sjoerg#ifdef DEBUG
108624139Sjoerg    fprintf(debug, "line_update, starting at %d\n", start);
108724139Sjoerg    fputs(old, debug);
108824139Sjoerg    fputc('\n', debug);
108924139Sjoerg    fputs(new, debug);
109024139Sjoerg    fputs("\n-\n", debug);
109124139Sjoerg#endif
109224139Sjoerg
109324139Sjoerg    /* start things off on the right foot		    */
109424139Sjoerg    /* this is to make sure the invariants get set up right */
109524139Sjoerg    if ((ch = *new++) != *old)
109624139Sjoerg    {
109724139Sjoerg	if (line - lastline == 1 && start == 0)
109824139Sjoerg	{
109924139Sjoerg	    putchar('\n');
110024139Sjoerg	}
110124139Sjoerg	else
110224139Sjoerg	{
110324139Sjoerg	    Move_to(start, line);
110424139Sjoerg	}
110524139Sjoerg	cursor_on_line = Yes;
110624139Sjoerg	putchar(ch);
110724139Sjoerg	*old = ch;
110824139Sjoerg	lastcol = 1;
110924139Sjoerg    }
111024139Sjoerg    old++;
111124139Sjoerg
111224139Sjoerg    /*
111324139Sjoerg     *  main loop -- check each character.  If the old and new aren't the
111424139Sjoerg     *	same, then update the display.  When the distance from the
111524139Sjoerg     *	current cursor position to the new change is small enough,
111624139Sjoerg     *	the characters that belong there are written to move the
111724139Sjoerg     *	cursor over.
111824139Sjoerg     *
111924139Sjoerg     *	Invariants:
112024139Sjoerg     *	    lastcol is the column where the cursor currently is sitting
112124139Sjoerg     *		(always one beyond the end of the last mismatch).
112224139Sjoerg     */
112324139Sjoerg    do		/* yes, a do...while */
112424139Sjoerg    {
112524139Sjoerg	if ((ch = *new++) != *old)
112624139Sjoerg	{
112724139Sjoerg	    /* new character is different from old	  */
112824139Sjoerg	    /* make sure the cursor is on top of this character */
112924139Sjoerg	    diff = newcol - lastcol;
113024139Sjoerg	    if (diff > 0)
113124139Sjoerg	    {
113224139Sjoerg		/* some motion is required--figure out which is shorter */
113324139Sjoerg		if (diff < 6 && cursor_on_line)
113424139Sjoerg		{
113524139Sjoerg		    /* overwrite old stuff--get it out of the old buffer */
113624139Sjoerg		    printf("%.*s", diff, &current[lastcol-start]);
113724139Sjoerg		}
113824139Sjoerg		else
113924139Sjoerg		{
114024139Sjoerg		    /* use cursor addressing */
114124139Sjoerg		    Move_to(newcol, line);
114224139Sjoerg		    cursor_on_line = Yes;
114324139Sjoerg		}
114424139Sjoerg		/* remember where the cursor is */
114524139Sjoerg		lastcol = newcol + 1;
114624139Sjoerg	    }
114724139Sjoerg	    else
114824139Sjoerg	    {
114924139Sjoerg		/* already there, update position */
115024139Sjoerg		lastcol++;
115124139Sjoerg	    }
115224139Sjoerg
115324139Sjoerg	    /* write what we need to */
115424139Sjoerg	    if (ch == '\0')
115524139Sjoerg	    {
115624139Sjoerg		/* at the end--terminate with a clear-to-end-of-line */
115724139Sjoerg		(void) clear_eol(strlen(old));
115824139Sjoerg	    }
115924139Sjoerg	    else
116024139Sjoerg	    {
116124139Sjoerg		/* write the new character */
116224139Sjoerg		putchar(ch);
116324139Sjoerg	    }
116424139Sjoerg	    /* put the new character in the screen buffer */
116524139Sjoerg	    *old = ch;
116624139Sjoerg	}
116724139Sjoerg
116824139Sjoerg	/* update working column and screen buffer pointer */
116924139Sjoerg	newcol++;
117024139Sjoerg	old++;
117124139Sjoerg
117224139Sjoerg    } while (ch != '\0');
117324139Sjoerg
117424139Sjoerg    /* zero out the rest of the line buffer -- MUST BE DONE! */
117524139Sjoerg    diff = display_width - newcol;
117624139Sjoerg    if (diff > 0)
117724139Sjoerg    {
117824139Sjoerg	memzero(old, diff);
117924139Sjoerg    }
118024139Sjoerg
118124139Sjoerg    /* remember where the current line is */
118224139Sjoerg    if (cursor_on_line)
118324139Sjoerg    {
118424139Sjoerg	lastline = line;
118524139Sjoerg    }
118624139Sjoerg}
118724139Sjoerg
118824139Sjoerg/*
118924139Sjoerg *  printable(str) - make the string pointed to by "str" into one that is
119024139Sjoerg *	printable (i.e.: all ascii), by converting all non-printable
119124139Sjoerg *	characters into '?'.  Replacements are done in place and a pointer
119224139Sjoerg *	to the original buffer is returned.
119324139Sjoerg */
119424139Sjoerg
119524139Sjoergchar *printable(str)
119624139Sjoerg
119724139Sjoergchar *str;
119824139Sjoerg
119924139Sjoerg{
120024139Sjoerg    register char *ptr;
120124139Sjoerg    register char ch;
120224139Sjoerg
120324139Sjoerg    ptr = str;
120424139Sjoerg    while ((ch = *ptr) != '\0')
120524139Sjoerg    {
120624139Sjoerg	if (!isprint(ch))
120724139Sjoerg	{
120824139Sjoerg	    *ptr = '?';
120924139Sjoerg	}
121024139Sjoerg	ptr++;
121124139Sjoerg    }
121224139Sjoerg    return(str);
121324139Sjoerg}
1214