13be6ef06SEitan Adler /* 23be6ef06SEitan Adler * Top users/processes display for Unix 33be6ef06SEitan Adler * Version 3 43be6ef06SEitan Adler * 53be6ef06SEitan Adler * This program may be freely redistributed, 6c51e28f4SEitan 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> 290059e710SEitan Adler #include <unistd.h> 300059e710SEitan Adler 313be6ef06SEitan Adler #include "screen.h" 320059e710SEitan 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; 401b7645c6SEitan Adler static char termcap_buf[1024]; 411b7645c6SEitan Adler static char string_buffer[1024]; 421b7645c6SEitan Adler static char home[15]; 431b7645c6SEitan Adler static char lower_left[15]; 443be6ef06SEitan Adler char *clear_line; 451b7645c6SEitan Adler static char *clear_screen; 463be6ef06SEitan Adler char *clear_to_end; 473be6ef06SEitan Adler char *cursor_motion; 481b7645c6SEitan Adler static char *start_standout; 491b7645c6SEitan Adler static char *end_standout; 501b7645c6SEitan Adler static char *terminal_init; 511b7645c6SEitan Adler static char *terminal_end; 523be6ef06SEitan Adler 533be6ef06SEitan Adler static struct termios old_settings; 543be6ef06SEitan Adler static struct termios new_settings; 550b2f6ed1SEitan Adler static char is_a_terminal = false; 563be6ef06SEitan Adler 57*32497673SDaichi GOTO #define NON_INTERACTIVE_MODE_VIRTUAL_SCREEN_WIDTH 1024 58*32497673SDaichi GOTO 593be6ef06SEitan Adler void 605c66dcc0SEitan Adler init_termcap(bool interactive) 613be6ef06SEitan Adler { 623be6ef06SEitan Adler char *bufptr; 633be6ef06SEitan Adler char *PCptr; 643be6ef06SEitan Adler char *term_name; 653be6ef06SEitan Adler int status; 663be6ef06SEitan Adler 670a59db87SDaichi GOTO screen_width = 0; 683be6ef06SEitan Adler screen_length = 0; 693be6ef06SEitan Adler 703be6ef06SEitan Adler if (!interactive) 713be6ef06SEitan Adler { 723be6ef06SEitan Adler /* pretend we have a dumb terminal */ 73*32497673SDaichi GOTO screen_width = NON_INTERACTIVE_MODE_VIRTUAL_SCREEN_WIDTH; 740b2f6ed1SEitan Adler smart_terminal = false; 753be6ef06SEitan Adler return; 763be6ef06SEitan Adler } 773be6ef06SEitan Adler 783be6ef06SEitan Adler /* assume we have a smart terminal until proven otherwise */ 790b2f6ed1SEitan Adler smart_terminal = true; 803be6ef06SEitan Adler 813be6ef06SEitan Adler /* get the terminal name */ 823be6ef06SEitan Adler term_name = getenv("TERM"); 833be6ef06SEitan Adler 843be6ef06SEitan Adler /* if there is no TERM, assume it's a dumb terminal */ 853be6ef06SEitan Adler /* patch courtesy of Sam Horrocks at telegraph.ics.uci.edu */ 863be6ef06SEitan Adler if (term_name == NULL) 873be6ef06SEitan Adler { 880b2f6ed1SEitan Adler smart_terminal = false; 893be6ef06SEitan Adler return; 903be6ef06SEitan Adler } 913be6ef06SEitan Adler 923be6ef06SEitan Adler /* now get the termcap entry */ 933be6ef06SEitan Adler if ((status = tgetent(termcap_buf, term_name)) != 1) 943be6ef06SEitan Adler { 953be6ef06SEitan Adler if (status == -1) 963be6ef06SEitan Adler { 973be6ef06SEitan Adler fprintf(stderr, "%s: can't open termcap file\n", myname); 983be6ef06SEitan Adler } 993be6ef06SEitan Adler else 1003be6ef06SEitan Adler { 1013be6ef06SEitan Adler fprintf(stderr, "%s: no termcap entry for a `%s' terminal\n", 1023be6ef06SEitan Adler myname, term_name); 1033be6ef06SEitan Adler } 1043be6ef06SEitan Adler 1053be6ef06SEitan Adler /* pretend it's dumb and proceed */ 1060b2f6ed1SEitan Adler smart_terminal = false; 1073be6ef06SEitan Adler return; 1083be6ef06SEitan Adler } 1093be6ef06SEitan Adler 1103be6ef06SEitan Adler /* "hardcopy" immediately indicates a very stupid terminal */ 1113be6ef06SEitan Adler if (tgetflag("hc")) 1123be6ef06SEitan Adler { 1130b2f6ed1SEitan Adler smart_terminal = false; 1143be6ef06SEitan Adler return; 1153be6ef06SEitan Adler } 1163be6ef06SEitan Adler 1173be6ef06SEitan Adler /* set up common terminal capabilities */ 1183be6ef06SEitan Adler if ((screen_length = tgetnum("li")) <= 0) 1193be6ef06SEitan Adler { 1203be6ef06SEitan Adler screen_length = smart_terminal = 0; 1213be6ef06SEitan Adler return; 1223be6ef06SEitan Adler } 1233be6ef06SEitan Adler 1243be6ef06SEitan Adler /* screen_width is a little different */ 1253be6ef06SEitan Adler if ((screen_width = tgetnum("co")) == -1) 1263be6ef06SEitan Adler { 1273be6ef06SEitan Adler screen_width = 79; 1283be6ef06SEitan Adler } 1293be6ef06SEitan Adler else 1303be6ef06SEitan Adler { 1313be6ef06SEitan Adler screen_width -= 1; 1323be6ef06SEitan Adler } 1333be6ef06SEitan Adler 1343be6ef06SEitan Adler /* terminals that overstrike need special attention */ 1353be6ef06SEitan Adler overstrike = tgetflag("os"); 1363be6ef06SEitan Adler 1373be6ef06SEitan Adler /* initialize the pointer into the termcap string buffer */ 1383be6ef06SEitan Adler bufptr = string_buffer; 1393be6ef06SEitan Adler 1403be6ef06SEitan Adler /* get "ce", clear to end */ 1413be6ef06SEitan Adler if (!overstrike) 1423be6ef06SEitan Adler { 1433be6ef06SEitan Adler clear_line = tgetstr("ce", &bufptr); 1443be6ef06SEitan Adler } 1453be6ef06SEitan Adler 1463be6ef06SEitan Adler /* get necessary capabilities */ 1473be6ef06SEitan Adler if ((clear_screen = tgetstr("cl", &bufptr)) == NULL || 1483be6ef06SEitan Adler (cursor_motion = tgetstr("cm", &bufptr)) == NULL) 1493be6ef06SEitan Adler { 1500b2f6ed1SEitan Adler smart_terminal = false; 1513be6ef06SEitan Adler return; 1523be6ef06SEitan Adler } 1533be6ef06SEitan Adler 1543be6ef06SEitan Adler /* get some more sophisticated stuff -- these are optional */ 1553be6ef06SEitan Adler clear_to_end = tgetstr("cd", &bufptr); 1563be6ef06SEitan Adler terminal_init = tgetstr("ti", &bufptr); 1573be6ef06SEitan Adler terminal_end = tgetstr("te", &bufptr); 1583be6ef06SEitan Adler start_standout = tgetstr("so", &bufptr); 1593be6ef06SEitan Adler end_standout = tgetstr("se", &bufptr); 1603be6ef06SEitan Adler 1613be6ef06SEitan Adler /* pad character */ 1623be6ef06SEitan Adler PC = (PCptr = tgetstr("pc", &bufptr)) ? *PCptr : 0; 1633be6ef06SEitan Adler 1643be6ef06SEitan Adler /* set convenience strings */ 1650059e710SEitan Adler strncpy(home, tgoto(cursor_motion, 0, 0), sizeof(home) - 1); 1663be6ef06SEitan Adler home[sizeof(home) - 1] = '\0'; 1673be6ef06SEitan Adler /* (lower_left is set in get_screensize) */ 1683be6ef06SEitan Adler 1693be6ef06SEitan Adler /* get the actual screen size with an ioctl, if needed */ 1703be6ef06SEitan Adler /* This may change screen_width and screen_length, and it always 1713be6ef06SEitan Adler sets lower_left. */ 1723be6ef06SEitan Adler get_screensize(); 1733be6ef06SEitan Adler 1743be6ef06SEitan Adler /* if stdout is not a terminal, pretend we are a dumb terminal */ 1750059e710SEitan Adler if (tcgetattr(STDOUT_FILENO, &old_settings) == -1) 1763be6ef06SEitan Adler { 1770b2f6ed1SEitan Adler smart_terminal = false; 1783be6ef06SEitan Adler } 1793be6ef06SEitan Adler } 1803be6ef06SEitan Adler 1813be6ef06SEitan Adler void 182f6234b51SEitan Adler init_screen(void) 1833be6ef06SEitan Adler { 1843be6ef06SEitan Adler /* get the old settings for safe keeping */ 1850059e710SEitan Adler if (tcgetattr(STDOUT_FILENO, &old_settings) != -1) 1863be6ef06SEitan Adler { 1873be6ef06SEitan Adler /* copy the settings so we can modify them */ 1883be6ef06SEitan Adler new_settings = old_settings; 1893be6ef06SEitan Adler 1903be6ef06SEitan Adler /* turn off ICANON, character echo and tab expansion */ 1913be6ef06SEitan Adler new_settings.c_lflag &= ~(ICANON|ECHO); 1923be6ef06SEitan Adler new_settings.c_oflag &= ~(TAB3); 1933be6ef06SEitan Adler new_settings.c_cc[VMIN] = 1; 1943be6ef06SEitan Adler new_settings.c_cc[VTIME] = 0; 1950059e710SEitan Adler tcsetattr(STDOUT_FILENO, TCSADRAIN, &new_settings); 1963be6ef06SEitan Adler 1973be6ef06SEitan Adler /* remember the erase and kill characters */ 1983be6ef06SEitan Adler ch_erase = old_settings.c_cc[VERASE]; 1993be6ef06SEitan Adler ch_kill = old_settings.c_cc[VKILL]; 2003be6ef06SEitan Adler 2013be6ef06SEitan Adler /* remember that it really is a terminal */ 2020b2f6ed1SEitan Adler is_a_terminal = true; 2033be6ef06SEitan Adler 2043be6ef06SEitan Adler /* send the termcap initialization string */ 2053be6ef06SEitan Adler putcap(terminal_init); 2063be6ef06SEitan Adler } 2073be6ef06SEitan Adler 2083be6ef06SEitan Adler if (!is_a_terminal) 2093be6ef06SEitan Adler { 2103be6ef06SEitan Adler /* not a terminal at all---consider it dumb */ 2110b2f6ed1SEitan Adler smart_terminal = false; 2123be6ef06SEitan Adler } 2133be6ef06SEitan Adler } 2143be6ef06SEitan Adler 2153be6ef06SEitan Adler void 216f6234b51SEitan Adler end_screen(void) 2173be6ef06SEitan Adler { 2183be6ef06SEitan Adler /* move to the lower left, clear the line and send "te" */ 2193be6ef06SEitan Adler if (smart_terminal) 2203be6ef06SEitan Adler { 2213be6ef06SEitan Adler putcap(lower_left); 2223be6ef06SEitan Adler putcap(clear_line); 2233be6ef06SEitan Adler fflush(stdout); 2243be6ef06SEitan Adler putcap(terminal_end); 2253be6ef06SEitan Adler } 2263be6ef06SEitan Adler 2273be6ef06SEitan Adler /* if we have settings to reset, then do so */ 2283be6ef06SEitan Adler if (is_a_terminal) 2293be6ef06SEitan Adler { 2300059e710SEitan Adler tcsetattr(STDOUT_FILENO, TCSADRAIN, &old_settings); 2313be6ef06SEitan Adler } 2323be6ef06SEitan Adler } 2333be6ef06SEitan Adler 2343be6ef06SEitan Adler void 235f6234b51SEitan Adler reinit_screen(void) 2363be6ef06SEitan Adler { 2373be6ef06SEitan Adler /* install our settings if it is a terminal */ 2383be6ef06SEitan Adler if (is_a_terminal) 2393be6ef06SEitan Adler { 2400059e710SEitan Adler tcsetattr(STDOUT_FILENO, TCSADRAIN, &new_settings); 2413be6ef06SEitan Adler } 2423be6ef06SEitan Adler 2433be6ef06SEitan Adler /* send init string */ 2443be6ef06SEitan Adler if (smart_terminal) 2453be6ef06SEitan Adler { 2463be6ef06SEitan Adler putcap(terminal_init); 2473be6ef06SEitan Adler } 2483be6ef06SEitan Adler } 2493be6ef06SEitan Adler 2503be6ef06SEitan Adler void 251f6234b51SEitan Adler get_screensize(void) 2523be6ef06SEitan Adler { 2533be6ef06SEitan Adler struct winsize ws; 2543be6ef06SEitan Adler 2553be6ef06SEitan Adler if (ioctl (1, TIOCGWINSZ, &ws) != -1) 2563be6ef06SEitan Adler { 2573be6ef06SEitan Adler if (ws.ws_row != 0) 2583be6ef06SEitan Adler { 2593be6ef06SEitan Adler screen_length = ws.ws_row; 2603be6ef06SEitan Adler } 2613be6ef06SEitan Adler if (ws.ws_col != 0) 2623be6ef06SEitan Adler { 2633be6ef06SEitan Adler screen_width = ws.ws_col - 1; 2643be6ef06SEitan Adler } 2653be6ef06SEitan Adler } 2663be6ef06SEitan Adler 2673be6ef06SEitan Adler 2683be6ef06SEitan Adler (void) strncpy(lower_left, tgoto(cursor_motion, 0, screen_length - 1), 2693be6ef06SEitan Adler sizeof(lower_left) - 1); 2703be6ef06SEitan Adler lower_left[sizeof(lower_left) - 1] = '\0'; 2713be6ef06SEitan Adler } 2723be6ef06SEitan Adler 2733be6ef06SEitan Adler void 2744fedcd49SEitan Adler top_standout(const char *msg) 2753be6ef06SEitan Adler { 2763be6ef06SEitan Adler if (smart_terminal) 2773be6ef06SEitan Adler { 2783be6ef06SEitan Adler putcap(start_standout); 2793be6ef06SEitan Adler fputs(msg, stdout); 2803be6ef06SEitan Adler putcap(end_standout); 2813be6ef06SEitan Adler } 2823be6ef06SEitan Adler else 2833be6ef06SEitan Adler { 2843be6ef06SEitan Adler fputs(msg, stdout); 2853be6ef06SEitan Adler } 2863be6ef06SEitan Adler } 2873be6ef06SEitan Adler 2883be6ef06SEitan Adler void 289f6234b51SEitan Adler top_clear(void) 2903be6ef06SEitan Adler { 2913be6ef06SEitan Adler if (smart_terminal) 2923be6ef06SEitan Adler { 2933be6ef06SEitan Adler putcap(clear_screen); 2943be6ef06SEitan Adler } 2953be6ef06SEitan Adler } 2963be6ef06SEitan Adler 2973be6ef06SEitan Adler int 2983be6ef06SEitan Adler clear_eol(int len) 2993be6ef06SEitan Adler { 3003be6ef06SEitan Adler if (smart_terminal && !overstrike && len > 0) 3013be6ef06SEitan Adler { 3023be6ef06SEitan Adler if (clear_line) 3033be6ef06SEitan Adler { 3043be6ef06SEitan Adler putcap(clear_line); 3053be6ef06SEitan Adler return(0); 3063be6ef06SEitan Adler } 3073be6ef06SEitan Adler else 3083be6ef06SEitan Adler { 3093be6ef06SEitan Adler while (len-- > 0) 3103be6ef06SEitan Adler { 3113be6ef06SEitan Adler putchar(' '); 3123be6ef06SEitan Adler } 3133be6ef06SEitan Adler return(1); 3143be6ef06SEitan Adler } 3153be6ef06SEitan Adler } 3163be6ef06SEitan Adler return(-1); 3173be6ef06SEitan Adler } 318