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