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
1065937Speter *
1165937Speter * $FreeBSD$
1224139Sjoerg */
1324139Sjoerg
1424139Sjoerg/*  This file contains the routines that interface to termcap and stty/gtty.
1524139Sjoerg *
1624139Sjoerg *  Paul Vixie, February 1987: converted to use ioctl() instead of stty/gtty.
1724139Sjoerg *
1824139Sjoerg *  I put in code to turn on the TOSTOP bit while top was running, but I
1924139Sjoerg *  didn't really like the results.  If you desire it, turn on the
2024139Sjoerg *  preprocessor variable "TOStop".   --wnl
2124139Sjoerg */
2224139Sjoerg
2324139Sjoerg#include "os.h"
2424139Sjoerg#include "top.h"
2524139Sjoerg
2624139Sjoerg#include <sys/ioctl.h>
2724139Sjoerg#ifdef CBREAK
2824139Sjoerg# include <sgtty.h>
2924139Sjoerg# define SGTTY
3024139Sjoerg#else
3124139Sjoerg# ifdef TCGETA
3224139Sjoerg#  define TERMIO
3324139Sjoerg#  include <termio.h>
3424139Sjoerg# else
3524139Sjoerg#  define TERMIOS
3624139Sjoerg#  include <termios.h>
3724139Sjoerg# endif
3824139Sjoerg#endif
3924139Sjoerg#if defined(TERMIO) || defined(TERMIOS)
4024139Sjoerg# ifndef TAB3
4124139Sjoerg#  ifdef OXTABS
4224139Sjoerg#   define TAB3 OXTABS
4324139Sjoerg#  else
4424139Sjoerg#   define TAB3 0
4524139Sjoerg#  endif
4624139Sjoerg# endif
4724139Sjoerg#endif
4824139Sjoerg#include "screen.h"
4924139Sjoerg#include "boolean.h"
5024139Sjoerg
5124139Sjoergextern char *myname;
5224139Sjoerg
5324139Sjoerg
5424139Sjoergint  overstrike;
5524139Sjoergint  screen_length;
5624139Sjoergint  screen_width;
5724139Sjoergchar ch_erase;
5824139Sjoergchar ch_kill;
5924139Sjoergchar smart_terminal;
6024139Sjoergchar PC;
6124139Sjoergchar *tgetstr();
6224139Sjoergchar *tgoto();
6324139Sjoergchar termcap_buf[1024];
6424139Sjoergchar string_buffer[1024];
6524139Sjoergchar home[15];
6624139Sjoergchar lower_left[15];
6724139Sjoergchar *clear_line;
6824139Sjoergchar *clear_screen;
6924139Sjoergchar *clear_to_end;
7024139Sjoergchar *cursor_motion;
7124139Sjoergchar *start_standout;
7224139Sjoergchar *end_standout;
7324139Sjoergchar *terminal_init;
7424139Sjoergchar *terminal_end;
7524139Sjoerg
7624139Sjoerg#ifdef SGTTY
7724139Sjoergstatic struct sgttyb old_settings;
7824139Sjoergstatic struct sgttyb new_settings;
7924139Sjoerg#endif
8024139Sjoerg#ifdef TERMIO
8124139Sjoergstatic struct termio old_settings;
8224139Sjoergstatic struct termio new_settings;
8324139Sjoerg#endif
8424139Sjoerg#ifdef TERMIOS
8524139Sjoergstatic struct termios old_settings;
8624139Sjoergstatic struct termios new_settings;
8724139Sjoerg#endif
8824139Sjoergstatic char is_a_terminal = No;
8924139Sjoerg#ifdef TOStop
9024139Sjoergstatic int old_lword;
9124139Sjoergstatic int new_lword;
9224139Sjoerg#endif
9324139Sjoerg
9424139Sjoerg#define	STDIN	0
9524139Sjoerg#define	STDOUT	1
9624139Sjoerg#define	STDERR	2
9724139Sjoerg
98210386Srpaulovoid
9924139Sjoerginit_termcap(interactive)
10024139Sjoerg
10124139Sjoergint interactive;
10224139Sjoerg
10324139Sjoerg{
10424139Sjoerg    char *bufptr;
10524139Sjoerg    char *PCptr;
10624139Sjoerg    char *term_name;
10724139Sjoerg    char *getenv();
10824139Sjoerg    int status;
10924139Sjoerg
11024139Sjoerg    /* set defaults in case we aren't smart */
11124139Sjoerg    screen_width = MAX_COLS;
11224139Sjoerg    screen_length = 0;
11324139Sjoerg
11424139Sjoerg    if (!interactive)
11524139Sjoerg    {
11624139Sjoerg	/* pretend we have a dumb terminal */
11724139Sjoerg	smart_terminal = No;
11824139Sjoerg	return;
11924139Sjoerg    }
12024139Sjoerg
12124139Sjoerg    /* assume we have a smart terminal until proven otherwise */
12224139Sjoerg    smart_terminal = Yes;
12324139Sjoerg
12424139Sjoerg    /* get the terminal name */
12524139Sjoerg    term_name = getenv("TERM");
12624139Sjoerg
12724139Sjoerg    /* if there is no TERM, assume it's a dumb terminal */
12824139Sjoerg    /* patch courtesy of Sam Horrocks at telegraph.ics.uci.edu */
12924139Sjoerg    if (term_name == NULL)
13024139Sjoerg    {
13124139Sjoerg	smart_terminal = No;
13224139Sjoerg	return;
13324139Sjoerg    }
13424139Sjoerg
13524139Sjoerg    /* now get the termcap entry */
13624139Sjoerg    if ((status = tgetent(termcap_buf, term_name)) != 1)
13724139Sjoerg    {
13824139Sjoerg	if (status == -1)
13924139Sjoerg	{
14024139Sjoerg	    fprintf(stderr, "%s: can't open termcap file\n", myname);
14124139Sjoerg	}
14224139Sjoerg	else
14324139Sjoerg	{
14424139Sjoerg	    fprintf(stderr, "%s: no termcap entry for a `%s' terminal\n",
14524139Sjoerg		    myname, term_name);
14624139Sjoerg	}
14724139Sjoerg
14824139Sjoerg	/* pretend it's dumb and proceed */
14924139Sjoerg	smart_terminal = No;
15024139Sjoerg	return;
15124139Sjoerg    }
15224139Sjoerg
15324139Sjoerg    /* "hardcopy" immediately indicates a very stupid terminal */
15424139Sjoerg    if (tgetflag("hc"))
15524139Sjoerg    {
15624139Sjoerg	smart_terminal = No;
15724139Sjoerg	return;
15824139Sjoerg    }
15924139Sjoerg
16024139Sjoerg    /* set up common terminal capabilities */
16124139Sjoerg    if ((screen_length = tgetnum("li")) <= 0)
16224139Sjoerg    {
16324139Sjoerg	screen_length = smart_terminal = 0;
16424139Sjoerg	return;
16524139Sjoerg    }
16624139Sjoerg
16724139Sjoerg    /* screen_width is a little different */
16824139Sjoerg    if ((screen_width = tgetnum("co")) == -1)
16924139Sjoerg    {
17024139Sjoerg	screen_width = 79;
17124139Sjoerg    }
17224139Sjoerg    else
17324139Sjoerg    {
17424139Sjoerg	screen_width -= 1;
17524139Sjoerg    }
17624139Sjoerg
17724139Sjoerg    /* terminals that overstrike need special attention */
17824139Sjoerg    overstrike = tgetflag("os");
17924139Sjoerg
18024139Sjoerg    /* initialize the pointer into the termcap string buffer */
18124139Sjoerg    bufptr = string_buffer;
18224139Sjoerg
18324139Sjoerg    /* get "ce", clear to end */
18424139Sjoerg    if (!overstrike)
18524139Sjoerg    {
18624139Sjoerg	clear_line = tgetstr("ce", &bufptr);
18724139Sjoerg    }
18824139Sjoerg
18924139Sjoerg    /* get necessary capabilities */
19024139Sjoerg    if ((clear_screen  = tgetstr("cl", &bufptr)) == NULL ||
19124139Sjoerg	(cursor_motion = tgetstr("cm", &bufptr)) == NULL)
19224139Sjoerg    {
19324139Sjoerg	smart_terminal = No;
19424139Sjoerg	return;
19524139Sjoerg    }
19624139Sjoerg
19724139Sjoerg    /* get some more sophisticated stuff -- these are optional */
19824139Sjoerg    clear_to_end   = tgetstr("cd", &bufptr);
19924139Sjoerg    terminal_init  = tgetstr("ti", &bufptr);
20024139Sjoerg    terminal_end   = tgetstr("te", &bufptr);
20124139Sjoerg    start_standout = tgetstr("so", &bufptr);
20224139Sjoerg    end_standout   = tgetstr("se", &bufptr);
20324139Sjoerg
20424139Sjoerg    /* pad character */
20524139Sjoerg    PC = (PCptr = tgetstr("pc", &bufptr)) ? *PCptr : 0;
20624139Sjoerg
20724139Sjoerg    /* set convenience strings */
20831520Simp    (void) strncpy(home, tgoto(cursor_motion, 0, 0), sizeof(home) - 1);
20931520Simp    home[sizeof(home) - 1] = '\0';
21024139Sjoerg    /* (lower_left is set in get_screensize) */
21124139Sjoerg
21224139Sjoerg    /* get the actual screen size with an ioctl, if needed */
21324139Sjoerg    /* This may change screen_width and screen_length, and it always
21424139Sjoerg       sets lower_left. */
21524139Sjoerg    get_screensize();
21624139Sjoerg
21724139Sjoerg    /* if stdout is not a terminal, pretend we are a dumb terminal */
21824139Sjoerg#ifdef SGTTY
21924139Sjoerg    if (ioctl(STDOUT, TIOCGETP, &old_settings) == -1)
22024139Sjoerg    {
22124139Sjoerg	smart_terminal = No;
22224139Sjoerg    }
22324139Sjoerg#endif
22424139Sjoerg#ifdef TERMIO
22524139Sjoerg    if (ioctl(STDOUT, TCGETA, &old_settings) == -1)
22624139Sjoerg    {
22724139Sjoerg	smart_terminal = No;
22824139Sjoerg    }
22924139Sjoerg#endif
23024139Sjoerg#ifdef TERMIOS
23124139Sjoerg    if (tcgetattr(STDOUT, &old_settings) == -1)
23224139Sjoerg    {
23324139Sjoerg	smart_terminal = No;
23424139Sjoerg    }
23524139Sjoerg#endif
23624139Sjoerg}
23724139Sjoerg
238301836Sngievoid
23924139Sjoerginit_screen()
24024139Sjoerg
24124139Sjoerg{
24224139Sjoerg    /* get the old settings for safe keeping */
24324139Sjoerg#ifdef SGTTY
24424139Sjoerg    if (ioctl(STDOUT, TIOCGETP, &old_settings) != -1)
24524139Sjoerg    {
24624139Sjoerg	/* copy the settings so we can modify them */
24724139Sjoerg	new_settings = old_settings;
24824139Sjoerg
24924139Sjoerg	/* turn on CBREAK and turn off character echo and tab expansion */
25024139Sjoerg	new_settings.sg_flags |= CBREAK;
25124139Sjoerg	new_settings.sg_flags &= ~(ECHO|XTABS);
25224139Sjoerg	(void) ioctl(STDOUT, TIOCSETP, &new_settings);
25324139Sjoerg
25424139Sjoerg	/* remember the erase and kill characters */
25524139Sjoerg	ch_erase = old_settings.sg_erase;
25624139Sjoerg	ch_kill  = old_settings.sg_kill;
25724139Sjoerg
25824139Sjoerg#ifdef TOStop
25924139Sjoerg	/* get the local mode word */
26024139Sjoerg	(void) ioctl(STDOUT, TIOCLGET, &old_lword);
26124139Sjoerg
26224139Sjoerg	/* modify it */
26324139Sjoerg	new_lword = old_lword | LTOSTOP;
26424139Sjoerg	(void) ioctl(STDOUT, TIOCLSET, &new_lword);
26524139Sjoerg#endif
26624139Sjoerg	/* remember that it really is a terminal */
26724139Sjoerg	is_a_terminal = Yes;
26824139Sjoerg
26924139Sjoerg	/* send the termcap initialization string */
27024139Sjoerg	putcap(terminal_init);
27124139Sjoerg    }
27224139Sjoerg#endif
27324139Sjoerg#ifdef TERMIO
27424139Sjoerg    if (ioctl(STDOUT, TCGETA, &old_settings) != -1)
27524139Sjoerg    {
27624139Sjoerg	/* copy the settings so we can modify them */
27724139Sjoerg	new_settings = old_settings;
27824139Sjoerg
27924139Sjoerg	/* turn off ICANON, character echo and tab expansion */
28024139Sjoerg	new_settings.c_lflag &= ~(ICANON|ECHO);
28124139Sjoerg	new_settings.c_oflag &= ~(TAB3);
28224139Sjoerg	new_settings.c_cc[VMIN] = 1;
28324139Sjoerg	new_settings.c_cc[VTIME] = 0;
28424139Sjoerg	(void) ioctl(STDOUT, TCSETA, &new_settings);
28524139Sjoerg
28624139Sjoerg	/* remember the erase and kill characters */
28724139Sjoerg	ch_erase = old_settings.c_cc[VERASE];
28824139Sjoerg	ch_kill  = old_settings.c_cc[VKILL];
28924139Sjoerg
29024139Sjoerg	/* remember that it really is a terminal */
29124139Sjoerg	is_a_terminal = Yes;
29224139Sjoerg
29324139Sjoerg	/* send the termcap initialization string */
29424139Sjoerg	putcap(terminal_init);
29524139Sjoerg    }
29624139Sjoerg#endif
29724139Sjoerg#ifdef TERMIOS
29824139Sjoerg    if (tcgetattr(STDOUT, &old_settings) != -1)
29924139Sjoerg    {
30024139Sjoerg	/* copy the settings so we can modify them */
30124139Sjoerg	new_settings = old_settings;
30224139Sjoerg
30324139Sjoerg	/* turn off ICANON, character echo and tab expansion */
30424139Sjoerg	new_settings.c_lflag &= ~(ICANON|ECHO);
30524139Sjoerg	new_settings.c_oflag &= ~(TAB3);
30624139Sjoerg	new_settings.c_cc[VMIN] = 1;
30724139Sjoerg	new_settings.c_cc[VTIME] = 0;
30824139Sjoerg	(void) tcsetattr(STDOUT, TCSADRAIN, &new_settings);
30924139Sjoerg
31024139Sjoerg	/* remember the erase and kill characters */
31124139Sjoerg	ch_erase = old_settings.c_cc[VERASE];
31224139Sjoerg	ch_kill  = old_settings.c_cc[VKILL];
31324139Sjoerg
31424139Sjoerg	/* remember that it really is a terminal */
31524139Sjoerg	is_a_terminal = Yes;
31624139Sjoerg
31724139Sjoerg	/* send the termcap initialization string */
31824139Sjoerg	putcap(terminal_init);
31924139Sjoerg    }
32024139Sjoerg#endif
32124139Sjoerg
32224139Sjoerg    if (!is_a_terminal)
32324139Sjoerg    {
32424139Sjoerg	/* not a terminal at all---consider it dumb */
32524139Sjoerg	smart_terminal = No;
32624139Sjoerg    }
32724139Sjoerg}
32824139Sjoerg
329301836Sngievoid
33024139Sjoergend_screen()
33124139Sjoerg
33224139Sjoerg{
33324139Sjoerg    /* move to the lower left, clear the line and send "te" */
33424139Sjoerg    if (smart_terminal)
33524139Sjoerg    {
33624139Sjoerg	putcap(lower_left);
33724139Sjoerg	putcap(clear_line);
33824139Sjoerg	fflush(stdout);
33924139Sjoerg	putcap(terminal_end);
34024139Sjoerg    }
34124139Sjoerg
34224139Sjoerg    /* if we have settings to reset, then do so */
34324139Sjoerg    if (is_a_terminal)
34424139Sjoerg    {
34524139Sjoerg#ifdef SGTTY
34624139Sjoerg	(void) ioctl(STDOUT, TIOCSETP, &old_settings);
34724139Sjoerg#ifdef TOStop
34824139Sjoerg	(void) ioctl(STDOUT, TIOCLSET, &old_lword);
34924139Sjoerg#endif
35024139Sjoerg#endif
35124139Sjoerg#ifdef TERMIO
35224139Sjoerg	(void) ioctl(STDOUT, TCSETA, &old_settings);
35324139Sjoerg#endif
35424139Sjoerg#ifdef TERMIOS
35524139Sjoerg	(void) tcsetattr(STDOUT, TCSADRAIN, &old_settings);
35624139Sjoerg#endif
35724139Sjoerg    }
35824139Sjoerg}
35924139Sjoerg
360301836Sngievoid
36124139Sjoergreinit_screen()
36224139Sjoerg
36324139Sjoerg{
36424139Sjoerg    /* install our settings if it is a terminal */
36524139Sjoerg    if (is_a_terminal)
36624139Sjoerg    {
36724139Sjoerg#ifdef SGTTY
36824139Sjoerg	(void) ioctl(STDOUT, TIOCSETP, &new_settings);
36924139Sjoerg#ifdef TOStop
37024139Sjoerg	(void) ioctl(STDOUT, TIOCLSET, &new_lword);
37124139Sjoerg#endif
37224139Sjoerg#endif
37324139Sjoerg#ifdef TERMIO
37424139Sjoerg	(void) ioctl(STDOUT, TCSETA, &new_settings);
37524139Sjoerg#endif
37624139Sjoerg#ifdef TERMIOS
37724139Sjoerg	(void) tcsetattr(STDOUT, TCSADRAIN, &new_settings);
37824139Sjoerg#endif
37924139Sjoerg    }
38024139Sjoerg
38124139Sjoerg    /* send init string */
38224139Sjoerg    if (smart_terminal)
38324139Sjoerg    {
38424139Sjoerg	putcap(terminal_init);
38524139Sjoerg    }
38624139Sjoerg}
38724139Sjoerg
388301836Sngievoid
38924139Sjoergget_screensize()
39024139Sjoerg
39124139Sjoerg{
39224139Sjoerg
39324139Sjoerg#ifdef TIOCGWINSZ
39424139Sjoerg
39524139Sjoerg    struct winsize ws;
39624139Sjoerg
39724139Sjoerg    if (ioctl (1, TIOCGWINSZ, &ws) != -1)
39824139Sjoerg    {
39924139Sjoerg	if (ws.ws_row != 0)
40024139Sjoerg	{
40124139Sjoerg	    screen_length = ws.ws_row;
40224139Sjoerg	}
40324139Sjoerg	if (ws.ws_col != 0)
40424139Sjoerg	{
40524139Sjoerg	    screen_width = ws.ws_col - 1;
40624139Sjoerg	}
40724139Sjoerg    }
40824139Sjoerg
40924139Sjoerg#else
41024139Sjoerg#ifdef TIOCGSIZE
41124139Sjoerg
41224139Sjoerg    struct ttysize ts;
41324139Sjoerg
41424139Sjoerg    if (ioctl (1, TIOCGSIZE, &ts) != -1)
41524139Sjoerg    {
41624139Sjoerg	if (ts.ts_lines != 0)
41724139Sjoerg	{
41824139Sjoerg	    screen_length = ts.ts_lines;
41924139Sjoerg	}
42024139Sjoerg	if (ts.ts_cols != 0)
42124139Sjoerg	{
42224139Sjoerg	    screen_width = ts.ts_cols - 1;
42324139Sjoerg	}
42424139Sjoerg    }
42524139Sjoerg
42624139Sjoerg#endif /* TIOCGSIZE */
42724139Sjoerg#endif /* TIOCGWINSZ */
42824139Sjoerg
42931520Simp    (void) strncpy(lower_left, tgoto(cursor_motion, 0, screen_length - 1),
43031520Simp	sizeof(lower_left) - 1);
43131520Simp    lower_left[sizeof(lower_left) - 1] = '\0';
43224139Sjoerg}
43324139Sjoerg
434301836Sngievoid
43524139Sjoergstandout(msg)
43624139Sjoerg
43724139Sjoergchar *msg;
43824139Sjoerg
43924139Sjoerg{
44024139Sjoerg    if (smart_terminal)
44124139Sjoerg    {
44224139Sjoerg	putcap(start_standout);
44324139Sjoerg	fputs(msg, stdout);
44424139Sjoerg	putcap(end_standout);
44524139Sjoerg    }
44624139Sjoerg    else
44724139Sjoerg    {
44824139Sjoerg	fputs(msg, stdout);
44924139Sjoerg    }
45024139Sjoerg}
45124139Sjoerg
452301836Sngievoid
45324139Sjoergclear()
45424139Sjoerg
45524139Sjoerg{
45624139Sjoerg    if (smart_terminal)
45724139Sjoerg    {
45824139Sjoerg	putcap(clear_screen);
45924139Sjoerg    }
46024139Sjoerg}
46124139Sjoerg
462301836Sngieint
46324139Sjoergclear_eol(len)
46424139Sjoerg
46524139Sjoergint len;
46624139Sjoerg
46724139Sjoerg{
46824139Sjoerg    if (smart_terminal && !overstrike && len > 0)
46924139Sjoerg    {
47024139Sjoerg	if (clear_line)
47124139Sjoerg	{
47224139Sjoerg	    putcap(clear_line);
47324139Sjoerg	    return(0);
47424139Sjoerg	}
47524139Sjoerg	else
47624139Sjoerg	{
47724139Sjoerg	    while (len-- > 0)
47824139Sjoerg	    {
47924139Sjoerg		putchar(' ');
48024139Sjoerg	    }
48124139Sjoerg	    return(1);
48224139Sjoerg	}
48324139Sjoerg    }
48424139Sjoerg    return(-1);
48524139Sjoerg}
48624139Sjoerg
487301836Sngievoid
48824139Sjoerggo_home()
48924139Sjoerg
49024139Sjoerg{
49124139Sjoerg    if (smart_terminal)
49224139Sjoerg    {
49324139Sjoerg	putcap(home);
49424139Sjoerg    }
49524139Sjoerg}
49624139Sjoerg
49724139Sjoerg/* This has to be defined as a subroutine for tputs (instead of a macro) */
49824139Sjoerg
499301836Sngievoid
50024139Sjoergputstdout(ch)
50124139Sjoerg
50224139Sjoergchar ch;
50324139Sjoerg
50424139Sjoerg{
50524139Sjoerg    putchar(ch);
50624139Sjoerg}
50724139Sjoerg
508