version 1.9, 2003/06/12 22:30:23 |
version 1.10, 2003/06/12 23:09:30 |
|
|
/* $OpenBSD$ */ |
/* $OpenBSD$ */ |
|
|
/* |
/* |
* Top users/processes display for Unix |
* Top users/processes display for Unix |
|
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
*/ |
*/ |
|
|
/* This file contains the routines that interface to termcap and stty/gtty. |
/* |
* |
* This file contains the routines that interface to termcap and stty/gtty. |
* Paul Vixie, February 1987: converted to use ioctl() instead of stty/gtty. |
* |
* |
* Paul Vixie, February 1987: converted to use ioctl() instead of stty/gtty. |
* I put in code to turn on the TOSTOP bit while top was running, but I |
* |
* didn't really like the results. If you desire it, turn on the |
* I put in code to turn on the TOSTOP bit while top was running, but I didn't |
* preprocessor variable "TOStop". --wnl |
* really like the results. If you desire it, turn on the preprocessor |
|
* variable "TOStop". --wnl |
*/ |
*/ |
|
|
#include <sys/types.h> |
#include <sys/types.h> |
|
|
#include "screen.h" |
#include "screen.h" |
#include "boolean.h" |
#include "boolean.h" |
|
|
extern char *myname; |
extern char *myname; |
|
|
int overstrike; |
int overstrike; |
int screen_length; |
int screen_length; |
int screen_width; |
int screen_width; |
char ch_erase; |
char ch_erase; |
char ch_kill; |
char ch_kill; |
char smart_terminal; |
char smart_terminal; |
char PC; |
char PC; |
char string_buffer[1024]; |
char string_buffer[1024]; |
char home[15]; |
char home[15]; |
char lower_left[15]; |
char lower_left[15]; |
char *clear_line; |
char *clear_line; |
char *clear_scr; |
char *clear_scr; |
char *clear_to_end; |
char *clear_to_end; |
char *cursor_motion; |
char *cursor_motion; |
char *start_standout; |
char *start_standout; |
char *end_standout; |
char *end_standout; |
char *terminal_init; |
char *terminal_init; |
char *terminal_end; |
char *terminal_end; |
short ospeed; |
short ospeed; |
|
|
static struct termios old_settings; |
static struct termios old_settings; |
static struct termios new_settings; |
static struct termios new_settings; |
|
|
static char is_a_terminal = No; |
static char is_a_terminal = No; |
|
|
void |
void |
init_termcap(int interactive) |
init_termcap(int interactive) |
{ |
{ |
char *bufptr; |
char *bufptr, *PCptr, *term_name; |
char *PCptr; |
int status; |
char *term_name; |
|
int status; |
|
|
|
/* set defaults in case we aren't smart */ |
/* set defaults in case we aren't smart */ |
screen_width = MAX_COLS; |
screen_width = MAX_COLS; |
screen_length = 0; |
screen_length = 0; |
|
|
if (!interactive) |
if (!interactive) { |
{ |
/* pretend we have a dumb terminal */ |
/* pretend we have a dumb terminal */ |
smart_terminal = No; |
smart_terminal = No; |
return; |
return; |
} |
} |
/* assume we have a smart terminal until proven otherwise */ |
|
smart_terminal = Yes; |
|
|
/* assume we have a smart terminal until proven otherwise */ |
/* get the terminal name */ |
smart_terminal = Yes; |
term_name = getenv("TERM"); |
|
|
/* get the terminal name */ |
/* if there is no TERM, assume it's a dumb terminal */ |
term_name = getenv("TERM"); |
/* patch courtesy of Sam Horrocks at telegraph.ics.uci.edu */ |
|
if (term_name == NULL) { |
|
smart_terminal = No; |
|
return; |
|
} |
|
|
/* if there is no TERM, assume it's a dumb terminal */ |
/* now get the termcap entry */ |
/* patch courtesy of Sam Horrocks at telegraph.ics.uci.edu */ |
if ((status = tgetent(NULL, term_name)) != 1) { |
if (term_name == NULL) |
if (status == -1) |
{ |
fprintf(stderr, "%s: can't open termcap file\n", myname); |
smart_terminal = No; |
else |
return; |
fprintf(stderr, "%s: no termcap entry for a `%s' terminal\n", |
} |
myname, term_name); |
|
|
/* now get the termcap entry */ |
/* pretend it's dumb and proceed */ |
if ((status = tgetent(NULL, term_name)) != 1) |
smart_terminal = No; |
{ |
return; |
if (status == -1) |
|
{ |
|
fprintf(stderr, "%s: can't open termcap file\n", myname); |
|
} |
} |
else |
|
{ |
/* "hardcopy" immediately indicates a very stupid terminal */ |
fprintf(stderr, "%s: no termcap entry for a `%s' terminal\n", |
if (tgetflag("hc")) { |
myname, term_name); |
smart_terminal = No; |
|
return; |
} |
} |
|
/* set up common terminal capabilities */ |
|
if ((screen_length = tgetnum("li")) <= Header_lines) { |
|
screen_length = smart_terminal = 0; |
|
return; |
|
} |
|
|
/* pretend it's dumb and proceed */ |
/* screen_width is a little different */ |
smart_terminal = No; |
if ((screen_width = tgetnum("co")) == -1) |
return; |
screen_width = 79; |
} |
else |
|
screen_width -= 1; |
|
|
/* "hardcopy" immediately indicates a very stupid terminal */ |
/* terminals that overstrike need special attention */ |
if (tgetflag("hc")) |
overstrike = tgetflag("os"); |
{ |
|
smart_terminal = No; |
|
return; |
|
} |
|
|
|
/* set up common terminal capabilities */ |
/* initialize the pointer into the termcap string buffer */ |
if ((screen_length = tgetnum("li")) <= Header_lines) |
bufptr = string_buffer; |
{ |
|
screen_length = smart_terminal = 0; |
|
return; |
|
} |
|
|
|
/* screen_width is a little different */ |
/* get "ce", clear to end */ |
if ((screen_width = tgetnum("co")) == -1) |
if (!overstrike) { |
{ |
clear_line = tgetstr("ce", &bufptr); |
screen_width = 79; |
} |
} |
/* get necessary capabilities */ |
else |
if ((clear_scr = tgetstr("cl", &bufptr)) == NULL || |
{ |
(cursor_motion = tgetstr("cm", &bufptr)) == NULL) { |
screen_width -= 1; |
smart_terminal = No; |
} |
return; |
|
} |
|
/* get some more sophisticated stuff -- these are optional */ |
|
clear_to_end = tgetstr("cd", &bufptr); |
|
terminal_init = tgetstr("ti", &bufptr); |
|
terminal_end = tgetstr("te", &bufptr); |
|
start_standout = tgetstr("so", &bufptr); |
|
end_standout = tgetstr("se", &bufptr); |
|
|
/* terminals that overstrike need special attention */ |
/* pad character */ |
overstrike = tgetflag("os"); |
PC = (PCptr = tgetstr("pc", &bufptr)) ? *PCptr : 0; |
|
|
/* initialize the pointer into the termcap string buffer */ |
/* set convenience strings */ |
bufptr = string_buffer; |
(void) strlcpy(home, tgoto(cursor_motion, 0, 0), sizeof(home)); |
|
/* (lower_left is set in get_screensize) */ |
|
|
/* get "ce", clear to end */ |
/* get the actual screen size with an ioctl, if needed */ |
if (!overstrike) |
/* |
{ |
* This may change screen_width and screen_length, and it always sets |
clear_line = tgetstr("ce", &bufptr); |
* lower_left. |
} |
*/ |
|
get_screensize(); |
|
|
/* get necessary capabilities */ |
/* if stdout is not a terminal, pretend we are a dumb terminal */ |
if ((clear_scr = tgetstr("cl", &bufptr)) == NULL || |
if (tcgetattr(STDOUT_FILENO, &old_settings) == -1) |
(cursor_motion = tgetstr("cm", &bufptr)) == NULL) |
smart_terminal = No; |
{ |
|
smart_terminal = No; |
|
return; |
|
} |
|
|
|
/* get some more sophisticated stuff -- these are optional */ |
|
clear_to_end = tgetstr("cd", &bufptr); |
|
terminal_init = tgetstr("ti", &bufptr); |
|
terminal_end = tgetstr("te", &bufptr); |
|
start_standout = tgetstr("so", &bufptr); |
|
end_standout = tgetstr("se", &bufptr); |
|
|
|
/* pad character */ |
|
PC = (PCptr = tgetstr("pc", &bufptr)) ? *PCptr : 0; |
|
|
|
/* set convenience strings */ |
|
(void) strncpy(home, tgoto(cursor_motion, 0, 0), sizeof (home) -1); |
|
home[sizeof (home) -1] = 0; |
|
/* (lower_left is set in get_screensize) */ |
|
|
|
/* get the actual screen size with an ioctl, if needed */ |
|
/* This may change screen_width and screen_length, and it always |
|
sets lower_left. */ |
|
get_screensize(); |
|
|
|
/* if stdout is not a terminal, pretend we are a dumb terminal */ |
|
if (tcgetattr(STDOUT_FILENO, &old_settings) == -1) |
|
{ |
|
smart_terminal = No; |
|
} |
|
} |
} |
|
|
void |
void |
init_screen(void) |
init_screen(void) |
{ |
{ |
/* get the old settings for safe keeping */ |
/* get the old settings for safe keeping */ |
if (tcgetattr(STDOUT_FILENO, &old_settings) != -1) |
if (tcgetattr(STDOUT_FILENO, &old_settings) != -1) { |
{ |
/* copy the settings so we can modify them */ |
/* copy the settings so we can modify them */ |
new_settings = old_settings; |
new_settings = old_settings; |
|
|
|
/* turn off ICANON, character echo and tab expansion */ |
/* turn off ICANON, character echo and tab expansion */ |
new_settings.c_lflag &= ~(ICANON|ECHO); |
new_settings.c_lflag &= ~(ICANON | ECHO); |
new_settings.c_oflag &= ~(OXTABS); |
new_settings.c_oflag &= ~(OXTABS); |
new_settings.c_cc[VMIN] = 1; |
new_settings.c_cc[VMIN] = 1; |
new_settings.c_cc[VTIME] = 0; |
new_settings.c_cc[VTIME] = 0; |
(void) tcsetattr(STDOUT_FILENO, TCSADRAIN, &new_settings); |
(void) tcsetattr(STDOUT_FILENO, TCSADRAIN, &new_settings); |
|
|
/* remember the erase and kill characters */ |
/* remember the erase and kill characters */ |
ch_erase = old_settings.c_cc[VERASE]; |
ch_erase = old_settings.c_cc[VERASE]; |
ch_kill = old_settings.c_cc[VKILL]; |
ch_kill = old_settings.c_cc[VKILL]; |
|
|
/* remember that it really is a terminal */ |
/* remember that it really is a terminal */ |
is_a_terminal = Yes; |
is_a_terminal = Yes; |
|
|
/* send the termcap initialization string */ |
/* send the termcap initialization string */ |
putcap(terminal_init); |
putcap(terminal_init); |
} |
} |
|
if (!is_a_terminal) { |
if (!is_a_terminal) |
/* not a terminal at all---consider it dumb */ |
{ |
smart_terminal = No; |
/* not a terminal at all---consider it dumb */ |
} |
smart_terminal = No; |
|
} |
|
} |
} |
|
|
void |
void |
end_screen(void) |
end_screen(void) |
{ |
{ |
/* move to the lower left, clear the line and send "te" */ |
/* move to the lower left, clear the line and send "te" */ |
if (smart_terminal) |
if (smart_terminal) { |
{ |
putcap(lower_left); |
putcap(lower_left); |
putcap(clear_line); |
putcap(clear_line); |
fflush(stdout); |
fflush(stdout); |
putcap(terminal_end); |
putcap(terminal_end); |
} |
} |
|
|
|
/* if we have settings to reset, then do so */ |
/* if we have settings to reset, then do so */ |
if (is_a_terminal) |
if (is_a_terminal) |
{ |
(void) tcsetattr(STDOUT_FILENO, TCSADRAIN, &old_settings); |
(void) tcsetattr(STDOUT_FILENO, TCSADRAIN, &old_settings); |
|
} |
|
} |
} |
|
|
void |
void |
reinit_screen(void) |
reinit_screen(void) |
{ |
{ |
/* install our settings if it is a terminal */ |
/* install our settings if it is a terminal */ |
if (is_a_terminal) |
if (is_a_terminal) |
{ |
(void) tcsetattr(STDOUT_FILENO, TCSADRAIN, &new_settings); |
(void) tcsetattr(STDOUT_FILENO, TCSADRAIN, &new_settings); |
|
} |
|
|
|
/* send init string */ |
/* send init string */ |
if (smart_terminal) |
if (smart_terminal) |
{ |
putcap(terminal_init); |
putcap(terminal_init); |
|
} |
|
} |
} |
|
|
void |
void |
get_screensize(void) |
get_screensize(void) |
{ |
{ |
struct winsize ws; |
struct winsize ws; |
|
|
if (ioctl (STDOUT_FILENO, TIOCGWINSZ, &ws) != -1) |
if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) != -1) { |
{ |
if (ws.ws_row != 0) |
if (ws.ws_row != 0) |
screen_length = ws.ws_row; |
{ |
if (ws.ws_col != 0) |
screen_length = ws.ws_row; |
screen_width = ws.ws_col - 1; |
} |
} |
if (ws.ws_col != 0) |
(void) strlcpy(lower_left, tgoto(cursor_motion, 0, screen_length - 1), |
{ |
sizeof(lower_left)); |
screen_width = ws.ws_col - 1; |
|
} |
|
} |
|
|
|
(void) strncpy(lower_left, tgoto(cursor_motion, 0, screen_length - 1), |
|
sizeof (lower_left) -1); |
|
lower_left[sizeof(lower_left) -1] = 0; |
|
} |
} |
|
|
void |
void |
standout(char *msg) |
standout(char *msg) |
{ |
{ |
if (smart_terminal) |
if (smart_terminal) { |
{ |
putcap(start_standout); |
putcap(start_standout); |
if (fputs(msg, stdout) == EOF) |
if (fputs(msg, stdout) == EOF) |
exit(1); |
exit(1); |
putcap(end_standout); |
putcap(end_standout); |
} else { |
} |
if (fputs(msg, stdout) == EOF) |
else |
exit(1); |
{ |
} |
if (fputs(msg, stdout) == EOF) |
|
exit(1); |
|
} |
|
} |
} |
|
|
void clear() |
void |
|
clear() |
{ |
{ |
if (smart_terminal) |
if (smart_terminal) |
{ |
putcap(clear_scr); |
putcap(clear_scr); |
|
} |
|
} |
} |
|
|
int |
int |
clear_eol(int len) |
clear_eol(int len) |
{ |
{ |
if (smart_terminal && !overstrike && len > 0) |
if (smart_terminal && !overstrike && len > 0) { |
{ |
if (clear_line) { |
if (clear_line) |
putcap(clear_line); |
{ |
return (0); |
putcap(clear_line); |
} else { |
return(0); |
while (len-- > 0) { |
|
if (putchar(' ') == EOF) |
|
exit(1); |
|
} |
|
return (1); |
|
} |
} |
} |
else |
return (-1); |
{ |
|
while (len-- > 0) |
|
{ |
|
if (putchar(' ') == EOF) |
|
exit(1); |
|
} |
|
return(1); |
|
} |
|
} |
|
return(-1); |
|
} |
} |
|
|
void |
void |
go_home(void) |
go_home(void) |
{ |
{ |
if (smart_terminal) |
if (smart_terminal) |
{ |
putcap(home); |
putcap(home); |
|
} |
|
} |
} |
|
|
/* This has to be defined as a subroutine for tputs (instead of a macro) */ |
/* This has to be defined as a subroutine for tputs (instead of a macro) */ |
|
|
int |
int |
putstdout(int ch) |
putstdout(int ch) |
{ |
{ |
int ret; |
int ret; |
|
|
ret = putchar(ch); |
ret = putchar(ch); |
if (ret == EOF) |
if (ret == EOF) |
exit(1); |
exit(1); |
return (ret); |
return (ret); |
} |
} |