13be6ef06SEitan Adler /* 23be6ef06SEitan Adler * Top users/processes display for Unix 33be6ef06SEitan Adler * Version 3 43be6ef06SEitan Adler * 53be6ef06SEitan Adler * This program may be freely redistributed, 63be6ef06SEitan Adler * but this entire comment MUST remain intact. 73be6ef06SEitan Adler * 83be6ef06SEitan Adler * Copyright (c) 1984, 1989, William LeFebvre, Rice University 93be6ef06SEitan Adler * Copyright (c) 1989, 1990, 1992, William LeFebvre, Northwestern University 103be6ef06SEitan Adler * 113be6ef06SEitan Adler * $FreeBSD$ 123be6ef06SEitan Adler */ 133be6ef06SEitan Adler 143be6ef06SEitan Adler /* This file contains the routines that interface to termcap and stty/gtty. 153be6ef06SEitan Adler * 163be6ef06SEitan Adler * Paul Vixie, February 1987: converted to use ioctl() instead of stty/gtty. 173be6ef06SEitan Adler * 183be6ef06SEitan Adler * I put in code to turn on the TOSTOP bit while top was running, but I 193be6ef06SEitan Adler * didn't really like the results. If you desire it, turn on the 203be6ef06SEitan Adler * preprocessor variable "TOStop". --wnl 213be6ef06SEitan Adler */ 223be6ef06SEitan Adler 233be6ef06SEitan Adler #include <sys/ioctl.h> 24666cf873SEitan Adler #include <stdlib.h> 25caee4883SEitan Adler #include <string.h> 263be6ef06SEitan Adler #include <termios.h> 273be6ef06SEitan Adler #include <curses.h> 283be6ef06SEitan Adler #include <termcap.h> 29*0059e710SEitan Adler #include <unistd.h> 30*0059e710SEitan Adler 313be6ef06SEitan Adler #include "screen.h" 32*0059e710SEitan Adler #include "top.h" 333be6ef06SEitan Adler 343be6ef06SEitan Adler int overstrike; 353be6ef06SEitan Adler int screen_length; 363be6ef06SEitan Adler int screen_width; 373be6ef06SEitan Adler char ch_erase; 383be6ef06SEitan Adler char ch_kill; 393be6ef06SEitan Adler char smart_terminal; 403be6ef06SEitan Adler char PC; 411b7645c6SEitan Adler static char termcap_buf[1024]; 421b7645c6SEitan Adler static char string_buffer[1024]; 431b7645c6SEitan Adler static char home[15]; 441b7645c6SEitan Adler static char lower_left[15]; 453be6ef06SEitan Adler char *clear_line; 461b7645c6SEitan Adler static char *clear_screen; 473be6ef06SEitan Adler char *clear_to_end; 483be6ef06SEitan Adler char *cursor_motion; 491b7645c6SEitan Adler static char *start_standout; 501b7645c6SEitan Adler static char *end_standout; 511b7645c6SEitan Adler static char *terminal_init; 521b7645c6SEitan Adler static char *terminal_end; 533be6ef06SEitan Adler 543be6ef06SEitan Adler static struct termios old_settings; 553be6ef06SEitan Adler static struct termios new_settings; 560b2f6ed1SEitan Adler static char is_a_terminal = false; 573be6ef06SEitan Adler 583be6ef06SEitan Adler void 59f6234b51SEitan Adler init_termcap(int interactive) 603be6ef06SEitan Adler { 613be6ef06SEitan Adler char *bufptr; 623be6ef06SEitan Adler char *PCptr; 633be6ef06SEitan Adler char *term_name; 643be6ef06SEitan Adler int status; 653be6ef06SEitan Adler 663be6ef06SEitan Adler /* set defaults in case we aren't smart */ 673be6ef06SEitan Adler screen_width = MAX_COLS; 683be6ef06SEitan Adler screen_length = 0; 693be6ef06SEitan Adler 703be6ef06SEitan Adler if (!interactive) 713be6ef06SEitan Adler { 723be6ef06SEitan Adler /* pretend we have a dumb terminal */ 730b2f6ed1SEitan Adler smart_terminal = false; 743be6ef06SEitan Adler return; 753be6ef06SEitan Adler } 763be6ef06SEitan Adler 773be6ef06SEitan Adler /* assume we have a smart terminal until proven otherwise */ 780b2f6ed1SEitan Adler smart_terminal = true; 793be6ef06SEitan Adler 803be6ef06SEitan Adler /* get the terminal name */ 813be6ef06SEitan Adler term_name = getenv("TERM"); 823be6ef06SEitan Adler 833be6ef06SEitan Adler /* if there is no TERM, assume it's a dumb terminal */ 843be6ef06SEitan Adler /* patch courtesy of Sam Horrocks at telegraph.ics.uci.edu */ 853be6ef06SEitan Adler if (term_name == NULL) 863be6ef06SEitan Adler { 870b2f6ed1SEitan Adler smart_terminal = false; 883be6ef06SEitan Adler return; 893be6ef06SEitan Adler } 903be6ef06SEitan Adler 913be6ef06SEitan Adler /* now get the termcap entry */ 923be6ef06SEitan Adler if ((status = tgetent(termcap_buf, term_name)) != 1) 933be6ef06SEitan Adler { 943be6ef06SEitan Adler if (status == -1) 953be6ef06SEitan Adler { 963be6ef06SEitan Adler fprintf(stderr, "%s: can't open termcap file\n", myname); 973be6ef06SEitan Adler } 983be6ef06SEitan Adler else 993be6ef06SEitan Adler { 1003be6ef06SEitan Adler fprintf(stderr, "%s: no termcap entry for a `%s' terminal\n", 1013be6ef06SEitan Adler myname, term_name); 1023be6ef06SEitan Adler } 1033be6ef06SEitan Adler 1043be6ef06SEitan Adler /* pretend it's dumb and proceed */ 1050b2f6ed1SEitan Adler smart_terminal = false; 1063be6ef06SEitan Adler return; 1073be6ef06SEitan Adler } 1083be6ef06SEitan Adler 1093be6ef06SEitan Adler /* "hardcopy" immediately indicates a very stupid terminal */ 1103be6ef06SEitan Adler if (tgetflag("hc")) 1113be6ef06SEitan Adler { 1120b2f6ed1SEitan Adler smart_terminal = false; 1133be6ef06SEitan Adler return; 1143be6ef06SEitan Adler } 1153be6ef06SEitan Adler 1163be6ef06SEitan Adler /* set up common terminal capabilities */ 1173be6ef06SEitan Adler if ((screen_length = tgetnum("li")) <= 0) 1183be6ef06SEitan Adler { 1193be6ef06SEitan Adler screen_length = smart_terminal = 0; 1203be6ef06SEitan Adler return; 1213be6ef06SEitan Adler } 1223be6ef06SEitan Adler 1233be6ef06SEitan Adler /* screen_width is a little different */ 1243be6ef06SEitan Adler if ((screen_width = tgetnum("co")) == -1) 1253be6ef06SEitan Adler { 1263be6ef06SEitan Adler screen_width = 79; 1273be6ef06SEitan Adler } 1283be6ef06SEitan Adler else 1293be6ef06SEitan Adler { 1303be6ef06SEitan Adler screen_width -= 1; 1313be6ef06SEitan Adler } 1323be6ef06SEitan Adler 1333be6ef06SEitan Adler /* terminals that overstrike need special attention */ 1343be6ef06SEitan Adler overstrike = tgetflag("os"); 1353be6ef06SEitan Adler 1363be6ef06SEitan Adler /* initialize the pointer into the termcap string buffer */ 1373be6ef06SEitan Adler bufptr = string_buffer; 1383be6ef06SEitan Adler 1393be6ef06SEitan Adler /* get "ce", clear to end */ 1403be6ef06SEitan Adler if (!overstrike) 1413be6ef06SEitan Adler { 1423be6ef06SEitan Adler clear_line = tgetstr("ce", &bufptr); 1433be6ef06SEitan Adler } 1443be6ef06SEitan Adler 1453be6ef06SEitan Adler /* get necessary capabilities */ 1463be6ef06SEitan Adler if ((clear_screen = tgetstr("cl", &bufptr)) == NULL || 1473be6ef06SEitan Adler (cursor_motion = tgetstr("cm", &bufptr)) == NULL) 1483be6ef06SEitan Adler { 1490b2f6ed1SEitan Adler smart_terminal = false; 1503be6ef06SEitan Adler return; 1513be6ef06SEitan Adler } 1523be6ef06SEitan Adler 1533be6ef06SEitan Adler /* get some more sophisticated stuff -- these are optional */ 1543be6ef06SEitan Adler clear_to_end = tgetstr("cd", &bufptr); 1553be6ef06SEitan Adler terminal_init = tgetstr("ti", &bufptr); 1563be6ef06SEitan Adler terminal_end = tgetstr("te", &bufptr); 1573be6ef06SEitan Adler start_standout = tgetstr("so", &bufptr); 1583be6ef06SEitan Adler end_standout = tgetstr("se", &bufptr); 1593be6ef06SEitan Adler 1603be6ef06SEitan Adler /* pad character */ 1613be6ef06SEitan Adler PC = (PCptr = tgetstr("pc", &bufptr)) ? *PCptr : 0; 1623be6ef06SEitan Adler 1633be6ef06SEitan Adler /* set convenience strings */ 164*0059e710SEitan Adler strncpy(home, tgoto(cursor_motion, 0, 0), sizeof(home) - 1); 1653be6ef06SEitan Adler home[sizeof(home) - 1] = '\0'; 1663be6ef06SEitan Adler /* (lower_left is set in get_screensize) */ 1673be6ef06SEitan Adler 1683be6ef06SEitan Adler /* get the actual screen size with an ioctl, if needed */ 1693be6ef06SEitan Adler /* This may change screen_width and screen_length, and it always 1703be6ef06SEitan Adler sets lower_left. */ 1713be6ef06SEitan Adler get_screensize(); 1723be6ef06SEitan Adler 1733be6ef06SEitan Adler /* if stdout is not a terminal, pretend we are a dumb terminal */ 174*0059e710SEitan Adler if (tcgetattr(STDOUT_FILENO, &old_settings) == -1) 1753be6ef06SEitan Adler { 1760b2f6ed1SEitan Adler smart_terminal = false; 1773be6ef06SEitan Adler } 1783be6ef06SEitan Adler } 1793be6ef06SEitan Adler 1803be6ef06SEitan Adler void 181f6234b51SEitan Adler init_screen(void) 1823be6ef06SEitan Adler { 1833be6ef06SEitan Adler /* get the old settings for safe keeping */ 184*0059e710SEitan Adler if (tcgetattr(STDOUT_FILENO, &old_settings) != -1) 1853be6ef06SEitan Adler { 1863be6ef06SEitan Adler /* copy the settings so we can modify them */ 1873be6ef06SEitan Adler new_settings = old_settings; 1883be6ef06SEitan Adler 1893be6ef06SEitan Adler /* turn off ICANON, character echo and tab expansion */ 1903be6ef06SEitan Adler new_settings.c_lflag &= ~(ICANON|ECHO); 1913be6ef06SEitan Adler new_settings.c_oflag &= ~(TAB3); 1923be6ef06SEitan Adler new_settings.c_cc[VMIN] = 1; 1933be6ef06SEitan Adler new_settings.c_cc[VTIME] = 0; 194*0059e710SEitan Adler tcsetattr(STDOUT_FILENO, TCSADRAIN, &new_settings); 1953be6ef06SEitan Adler 1963be6ef06SEitan Adler /* remember the erase and kill characters */ 1973be6ef06SEitan Adler ch_erase = old_settings.c_cc[VERASE]; 1983be6ef06SEitan Adler ch_kill = old_settings.c_cc[VKILL]; 1993be6ef06SEitan Adler 2003be6ef06SEitan Adler /* remember that it really is a terminal */ 2010b2f6ed1SEitan Adler is_a_terminal = true; 2023be6ef06SEitan Adler 2033be6ef06SEitan Adler /* send the termcap initialization string */ 2043be6ef06SEitan Adler putcap(terminal_init); 2053be6ef06SEitan Adler } 2063be6ef06SEitan Adler 2073be6ef06SEitan Adler if (!is_a_terminal) 2083be6ef06SEitan Adler { 2093be6ef06SEitan Adler /* not a terminal at all---consider it dumb */ 2100b2f6ed1SEitan Adler smart_terminal = false; 2113be6ef06SEitan Adler } 2123be6ef06SEitan Adler } 2133be6ef06SEitan Adler 2143be6ef06SEitan Adler void 215f6234b51SEitan Adler end_screen(void) 2163be6ef06SEitan Adler { 2173be6ef06SEitan Adler /* move to the lower left, clear the line and send "te" */ 2183be6ef06SEitan Adler if (smart_terminal) 2193be6ef06SEitan Adler { 2203be6ef06SEitan Adler putcap(lower_left); 2213be6ef06SEitan Adler putcap(clear_line); 2223be6ef06SEitan Adler fflush(stdout); 2233be6ef06SEitan Adler putcap(terminal_end); 2243be6ef06SEitan Adler } 2253be6ef06SEitan Adler 2263be6ef06SEitan Adler /* if we have settings to reset, then do so */ 2273be6ef06SEitan Adler if (is_a_terminal) 2283be6ef06SEitan Adler { 229*0059e710SEitan Adler tcsetattr(STDOUT_FILENO, TCSADRAIN, &old_settings); 2303be6ef06SEitan Adler } 2313be6ef06SEitan Adler } 2323be6ef06SEitan Adler 2333be6ef06SEitan Adler void 234f6234b51SEitan Adler reinit_screen(void) 2353be6ef06SEitan Adler { 2363be6ef06SEitan Adler /* install our settings if it is a terminal */ 2373be6ef06SEitan Adler if (is_a_terminal) 2383be6ef06SEitan Adler { 239*0059e710SEitan Adler tcsetattr(STDOUT_FILENO, TCSADRAIN, &new_settings); 2403be6ef06SEitan Adler } 2413be6ef06SEitan Adler 2423be6ef06SEitan Adler /* send init string */ 2433be6ef06SEitan Adler if (smart_terminal) 2443be6ef06SEitan Adler { 2453be6ef06SEitan Adler putcap(terminal_init); 2463be6ef06SEitan Adler } 2473be6ef06SEitan Adler } 2483be6ef06SEitan Adler 2493be6ef06SEitan Adler void 250f6234b51SEitan Adler get_screensize(void) 2513be6ef06SEitan Adler { 2523be6ef06SEitan Adler struct winsize ws; 2533be6ef06SEitan Adler 2543be6ef06SEitan Adler if (ioctl (1, TIOCGWINSZ, &ws) != -1) 2553be6ef06SEitan Adler { 2563be6ef06SEitan Adler if (ws.ws_row != 0) 2573be6ef06SEitan Adler { 2583be6ef06SEitan Adler screen_length = ws.ws_row; 2593be6ef06SEitan Adler } 2603be6ef06SEitan Adler if (ws.ws_col != 0) 2613be6ef06SEitan Adler { 2623be6ef06SEitan Adler screen_width = ws.ws_col - 1; 2633be6ef06SEitan Adler } 2643be6ef06SEitan Adler } 2653be6ef06SEitan Adler 2663be6ef06SEitan Adler 2673be6ef06SEitan Adler (void) strncpy(lower_left, tgoto(cursor_motion, 0, screen_length - 1), 2683be6ef06SEitan Adler sizeof(lower_left) - 1); 2693be6ef06SEitan Adler lower_left[sizeof(lower_left) - 1] = '\0'; 2703be6ef06SEitan Adler } 2713be6ef06SEitan Adler 2723be6ef06SEitan Adler void 2733be6ef06SEitan Adler top_standout(char *msg) 2743be6ef06SEitan Adler { 2753be6ef06SEitan Adler if (smart_terminal) 2763be6ef06SEitan Adler { 2773be6ef06SEitan Adler putcap(start_standout); 2783be6ef06SEitan Adler fputs(msg, stdout); 2793be6ef06SEitan Adler putcap(end_standout); 2803be6ef06SEitan Adler } 2813be6ef06SEitan Adler else 2823be6ef06SEitan Adler { 2833be6ef06SEitan Adler fputs(msg, stdout); 2843be6ef06SEitan Adler } 2853be6ef06SEitan Adler } 2863be6ef06SEitan Adler 2873be6ef06SEitan Adler void 288f6234b51SEitan Adler top_clear(void) 2893be6ef06SEitan Adler { 2903be6ef06SEitan Adler if (smart_terminal) 2913be6ef06SEitan Adler { 2923be6ef06SEitan Adler putcap(clear_screen); 2933be6ef06SEitan Adler } 2943be6ef06SEitan Adler } 2953be6ef06SEitan Adler 2963be6ef06SEitan Adler int 2973be6ef06SEitan Adler clear_eol(int len) 2983be6ef06SEitan Adler { 2993be6ef06SEitan Adler if (smart_terminal && !overstrike && len > 0) 3003be6ef06SEitan Adler { 3013be6ef06SEitan Adler if (clear_line) 3023be6ef06SEitan Adler { 3033be6ef06SEitan Adler putcap(clear_line); 3043be6ef06SEitan Adler return(0); 3053be6ef06SEitan Adler } 3063be6ef06SEitan Adler else 3073be6ef06SEitan Adler { 3083be6ef06SEitan Adler while (len-- > 0) 3093be6ef06SEitan Adler { 3103be6ef06SEitan Adler putchar(' '); 3113be6ef06SEitan Adler } 3123be6ef06SEitan Adler return(1); 3133be6ef06SEitan Adler } 3143be6ef06SEitan Adler } 3153be6ef06SEitan Adler return(-1); 3163be6ef06SEitan Adler } 3173be6ef06SEitan Adler 3183be6ef06SEitan Adler void 319f6234b51SEitan Adler go_home(void) 3203be6ef06SEitan Adler { 3213be6ef06SEitan Adler if (smart_terminal) 3223be6ef06SEitan Adler { 3233be6ef06SEitan Adler putcap(home); 3243be6ef06SEitan Adler } 3253be6ef06SEitan Adler } 3263be6ef06SEitan Adler 3273be6ef06SEitan Adler /* This has to be defined as a subroutine for tputs (instead of a macro) */ 3283be6ef06SEitan Adler 3293be6ef06SEitan Adler int 3303be6ef06SEitan Adler putstdout(int ch) 3313be6ef06SEitan Adler { 3323be6ef06SEitan Adler return putchar(ch); 3333be6ef06SEitan Adler } 334