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 573be6ef06SEitan Adler void 585c66dcc0SEitan Adler init_termcap(bool interactive) 593be6ef06SEitan Adler { 603be6ef06SEitan Adler char *bufptr; 613be6ef06SEitan Adler char *PCptr; 623be6ef06SEitan Adler char *term_name; 633be6ef06SEitan Adler int status; 643be6ef06SEitan Adler 65*0a59db87SDaichi GOTO screen_width = 0; 663be6ef06SEitan Adler screen_length = 0; 673be6ef06SEitan Adler 683be6ef06SEitan Adler if (!interactive) 693be6ef06SEitan Adler { 703be6ef06SEitan Adler /* pretend we have a dumb terminal */ 710b2f6ed1SEitan Adler smart_terminal = false; 723be6ef06SEitan Adler return; 733be6ef06SEitan Adler } 743be6ef06SEitan Adler 753be6ef06SEitan Adler /* assume we have a smart terminal until proven otherwise */ 760b2f6ed1SEitan Adler smart_terminal = true; 773be6ef06SEitan Adler 783be6ef06SEitan Adler /* get the terminal name */ 793be6ef06SEitan Adler term_name = getenv("TERM"); 803be6ef06SEitan Adler 813be6ef06SEitan Adler /* if there is no TERM, assume it's a dumb terminal */ 823be6ef06SEitan Adler /* patch courtesy of Sam Horrocks at telegraph.ics.uci.edu */ 833be6ef06SEitan Adler if (term_name == NULL) 843be6ef06SEitan Adler { 850b2f6ed1SEitan Adler smart_terminal = false; 863be6ef06SEitan Adler return; 873be6ef06SEitan Adler } 883be6ef06SEitan Adler 893be6ef06SEitan Adler /* now get the termcap entry */ 903be6ef06SEitan Adler if ((status = tgetent(termcap_buf, term_name)) != 1) 913be6ef06SEitan Adler { 923be6ef06SEitan Adler if (status == -1) 933be6ef06SEitan Adler { 943be6ef06SEitan Adler fprintf(stderr, "%s: can't open termcap file\n", myname); 953be6ef06SEitan Adler } 963be6ef06SEitan Adler else 973be6ef06SEitan Adler { 983be6ef06SEitan Adler fprintf(stderr, "%s: no termcap entry for a `%s' terminal\n", 993be6ef06SEitan Adler myname, term_name); 1003be6ef06SEitan Adler } 1013be6ef06SEitan Adler 1023be6ef06SEitan Adler /* pretend it's dumb and proceed */ 1030b2f6ed1SEitan Adler smart_terminal = false; 1043be6ef06SEitan Adler return; 1053be6ef06SEitan Adler } 1063be6ef06SEitan Adler 1073be6ef06SEitan Adler /* "hardcopy" immediately indicates a very stupid terminal */ 1083be6ef06SEitan Adler if (tgetflag("hc")) 1093be6ef06SEitan Adler { 1100b2f6ed1SEitan Adler smart_terminal = false; 1113be6ef06SEitan Adler return; 1123be6ef06SEitan Adler } 1133be6ef06SEitan Adler 1143be6ef06SEitan Adler /* set up common terminal capabilities */ 1153be6ef06SEitan Adler if ((screen_length = tgetnum("li")) <= 0) 1163be6ef06SEitan Adler { 1173be6ef06SEitan Adler screen_length = smart_terminal = 0; 1183be6ef06SEitan Adler return; 1193be6ef06SEitan Adler } 1203be6ef06SEitan Adler 1213be6ef06SEitan Adler /* screen_width is a little different */ 1223be6ef06SEitan Adler if ((screen_width = tgetnum("co")) == -1) 1233be6ef06SEitan Adler { 1243be6ef06SEitan Adler screen_width = 79; 1253be6ef06SEitan Adler } 1263be6ef06SEitan Adler else 1273be6ef06SEitan Adler { 1283be6ef06SEitan Adler screen_width -= 1; 1293be6ef06SEitan Adler } 1303be6ef06SEitan Adler 1313be6ef06SEitan Adler /* terminals that overstrike need special attention */ 1323be6ef06SEitan Adler overstrike = tgetflag("os"); 1333be6ef06SEitan Adler 1343be6ef06SEitan Adler /* initialize the pointer into the termcap string buffer */ 1353be6ef06SEitan Adler bufptr = string_buffer; 1363be6ef06SEitan Adler 1373be6ef06SEitan Adler /* get "ce", clear to end */ 1383be6ef06SEitan Adler if (!overstrike) 1393be6ef06SEitan Adler { 1403be6ef06SEitan Adler clear_line = tgetstr("ce", &bufptr); 1413be6ef06SEitan Adler } 1423be6ef06SEitan Adler 1433be6ef06SEitan Adler /* get necessary capabilities */ 1443be6ef06SEitan Adler if ((clear_screen = tgetstr("cl", &bufptr)) == NULL || 1453be6ef06SEitan Adler (cursor_motion = tgetstr("cm", &bufptr)) == NULL) 1463be6ef06SEitan Adler { 1470b2f6ed1SEitan Adler smart_terminal = false; 1483be6ef06SEitan Adler return; 1493be6ef06SEitan Adler } 1503be6ef06SEitan Adler 1513be6ef06SEitan Adler /* get some more sophisticated stuff -- these are optional */ 1523be6ef06SEitan Adler clear_to_end = tgetstr("cd", &bufptr); 1533be6ef06SEitan Adler terminal_init = tgetstr("ti", &bufptr); 1543be6ef06SEitan Adler terminal_end = tgetstr("te", &bufptr); 1553be6ef06SEitan Adler start_standout = tgetstr("so", &bufptr); 1563be6ef06SEitan Adler end_standout = tgetstr("se", &bufptr); 1573be6ef06SEitan Adler 1583be6ef06SEitan Adler /* pad character */ 1593be6ef06SEitan Adler PC = (PCptr = tgetstr("pc", &bufptr)) ? *PCptr : 0; 1603be6ef06SEitan Adler 1613be6ef06SEitan Adler /* set convenience strings */ 1620059e710SEitan Adler strncpy(home, tgoto(cursor_motion, 0, 0), sizeof(home) - 1); 1633be6ef06SEitan Adler home[sizeof(home) - 1] = '\0'; 1643be6ef06SEitan Adler /* (lower_left is set in get_screensize) */ 1653be6ef06SEitan Adler 1663be6ef06SEitan Adler /* get the actual screen size with an ioctl, if needed */ 1673be6ef06SEitan Adler /* This may change screen_width and screen_length, and it always 1683be6ef06SEitan Adler sets lower_left. */ 1693be6ef06SEitan Adler get_screensize(); 1703be6ef06SEitan Adler 1713be6ef06SEitan Adler /* if stdout is not a terminal, pretend we are a dumb terminal */ 1720059e710SEitan Adler if (tcgetattr(STDOUT_FILENO, &old_settings) == -1) 1733be6ef06SEitan Adler { 1740b2f6ed1SEitan Adler smart_terminal = false; 1753be6ef06SEitan Adler } 1763be6ef06SEitan Adler } 1773be6ef06SEitan Adler 1783be6ef06SEitan Adler void 179f6234b51SEitan Adler init_screen(void) 1803be6ef06SEitan Adler { 1813be6ef06SEitan Adler /* get the old settings for safe keeping */ 1820059e710SEitan Adler if (tcgetattr(STDOUT_FILENO, &old_settings) != -1) 1833be6ef06SEitan Adler { 1843be6ef06SEitan Adler /* copy the settings so we can modify them */ 1853be6ef06SEitan Adler new_settings = old_settings; 1863be6ef06SEitan Adler 1873be6ef06SEitan Adler /* turn off ICANON, character echo and tab expansion */ 1883be6ef06SEitan Adler new_settings.c_lflag &= ~(ICANON|ECHO); 1893be6ef06SEitan Adler new_settings.c_oflag &= ~(TAB3); 1903be6ef06SEitan Adler new_settings.c_cc[VMIN] = 1; 1913be6ef06SEitan Adler new_settings.c_cc[VTIME] = 0; 1920059e710SEitan Adler tcsetattr(STDOUT_FILENO, TCSADRAIN, &new_settings); 1933be6ef06SEitan Adler 1943be6ef06SEitan Adler /* remember the erase and kill characters */ 1953be6ef06SEitan Adler ch_erase = old_settings.c_cc[VERASE]; 1963be6ef06SEitan Adler ch_kill = old_settings.c_cc[VKILL]; 1973be6ef06SEitan Adler 1983be6ef06SEitan Adler /* remember that it really is a terminal */ 1990b2f6ed1SEitan Adler is_a_terminal = true; 2003be6ef06SEitan Adler 2013be6ef06SEitan Adler /* send the termcap initialization string */ 2023be6ef06SEitan Adler putcap(terminal_init); 2033be6ef06SEitan Adler } 2043be6ef06SEitan Adler 2053be6ef06SEitan Adler if (!is_a_terminal) 2063be6ef06SEitan Adler { 2073be6ef06SEitan Adler /* not a terminal at all---consider it dumb */ 2080b2f6ed1SEitan Adler smart_terminal = false; 2093be6ef06SEitan Adler } 2103be6ef06SEitan Adler } 2113be6ef06SEitan Adler 2123be6ef06SEitan Adler void 213f6234b51SEitan Adler end_screen(void) 2143be6ef06SEitan Adler { 2153be6ef06SEitan Adler /* move to the lower left, clear the line and send "te" */ 2163be6ef06SEitan Adler if (smart_terminal) 2173be6ef06SEitan Adler { 2183be6ef06SEitan Adler putcap(lower_left); 2193be6ef06SEitan Adler putcap(clear_line); 2203be6ef06SEitan Adler fflush(stdout); 2213be6ef06SEitan Adler putcap(terminal_end); 2223be6ef06SEitan Adler } 2233be6ef06SEitan Adler 2243be6ef06SEitan Adler /* if we have settings to reset, then do so */ 2253be6ef06SEitan Adler if (is_a_terminal) 2263be6ef06SEitan Adler { 2270059e710SEitan Adler tcsetattr(STDOUT_FILENO, TCSADRAIN, &old_settings); 2283be6ef06SEitan Adler } 2293be6ef06SEitan Adler } 2303be6ef06SEitan Adler 2313be6ef06SEitan Adler void 232f6234b51SEitan Adler reinit_screen(void) 2333be6ef06SEitan Adler { 2343be6ef06SEitan Adler /* install our settings if it is a terminal */ 2353be6ef06SEitan Adler if (is_a_terminal) 2363be6ef06SEitan Adler { 2370059e710SEitan Adler tcsetattr(STDOUT_FILENO, TCSADRAIN, &new_settings); 2383be6ef06SEitan Adler } 2393be6ef06SEitan Adler 2403be6ef06SEitan Adler /* send init string */ 2413be6ef06SEitan Adler if (smart_terminal) 2423be6ef06SEitan Adler { 2433be6ef06SEitan Adler putcap(terminal_init); 2443be6ef06SEitan Adler } 2453be6ef06SEitan Adler } 2463be6ef06SEitan Adler 2473be6ef06SEitan Adler void 248f6234b51SEitan Adler get_screensize(void) 2493be6ef06SEitan Adler { 2503be6ef06SEitan Adler struct winsize ws; 2513be6ef06SEitan Adler 2523be6ef06SEitan Adler if (ioctl (1, TIOCGWINSZ, &ws) != -1) 2533be6ef06SEitan Adler { 2543be6ef06SEitan Adler if (ws.ws_row != 0) 2553be6ef06SEitan Adler { 2563be6ef06SEitan Adler screen_length = ws.ws_row; 2573be6ef06SEitan Adler } 2583be6ef06SEitan Adler if (ws.ws_col != 0) 2593be6ef06SEitan Adler { 2603be6ef06SEitan Adler screen_width = ws.ws_col - 1; 2613be6ef06SEitan Adler } 2623be6ef06SEitan Adler } 2633be6ef06SEitan Adler 2643be6ef06SEitan Adler 2653be6ef06SEitan Adler (void) strncpy(lower_left, tgoto(cursor_motion, 0, screen_length - 1), 2663be6ef06SEitan Adler sizeof(lower_left) - 1); 2673be6ef06SEitan Adler lower_left[sizeof(lower_left) - 1] = '\0'; 2683be6ef06SEitan Adler } 2693be6ef06SEitan Adler 2703be6ef06SEitan Adler void 2714fedcd49SEitan Adler top_standout(const char *msg) 2723be6ef06SEitan Adler { 2733be6ef06SEitan Adler if (smart_terminal) 2743be6ef06SEitan Adler { 2753be6ef06SEitan Adler putcap(start_standout); 2763be6ef06SEitan Adler fputs(msg, stdout); 2773be6ef06SEitan Adler putcap(end_standout); 2783be6ef06SEitan Adler } 2793be6ef06SEitan Adler else 2803be6ef06SEitan Adler { 2813be6ef06SEitan Adler fputs(msg, stdout); 2823be6ef06SEitan Adler } 2833be6ef06SEitan Adler } 2843be6ef06SEitan Adler 2853be6ef06SEitan Adler void 286f6234b51SEitan Adler top_clear(void) 2873be6ef06SEitan Adler { 2883be6ef06SEitan Adler if (smart_terminal) 2893be6ef06SEitan Adler { 2903be6ef06SEitan Adler putcap(clear_screen); 2913be6ef06SEitan Adler } 2923be6ef06SEitan Adler } 2933be6ef06SEitan Adler 2943be6ef06SEitan Adler int 2953be6ef06SEitan Adler clear_eol(int len) 2963be6ef06SEitan Adler { 2973be6ef06SEitan Adler if (smart_terminal && !overstrike && len > 0) 2983be6ef06SEitan Adler { 2993be6ef06SEitan Adler if (clear_line) 3003be6ef06SEitan Adler { 3013be6ef06SEitan Adler putcap(clear_line); 3023be6ef06SEitan Adler return(0); 3033be6ef06SEitan Adler } 3043be6ef06SEitan Adler else 3053be6ef06SEitan Adler { 3063be6ef06SEitan Adler while (len-- > 0) 3073be6ef06SEitan Adler { 3083be6ef06SEitan Adler putchar(' '); 3093be6ef06SEitan Adler } 3103be6ef06SEitan Adler return(1); 3113be6ef06SEitan Adler } 3123be6ef06SEitan Adler } 3133be6ef06SEitan Adler return(-1); 3143be6ef06SEitan Adler } 315