1 /* 2 * Top users/processes display for Unix 3 * Version 3 4 * 5 * This program may be freely redistributed, 6 * but this entire comment MUST remain intact. 7 * 8 * Copyright (c) 1984, 1989, William LeFebvre, Rice University 9 * Copyright (c) 1989, 1990, 1992, William LeFebvre, Northwestern University 10 * 11 * $FreeBSD$ 12 */ 13 14 /* This file contains the routines that interface to termcap and stty/gtty. 15 * 16 * Paul Vixie, February 1987: converted to use ioctl() instead of stty/gtty. 17 * 18 * I put in code to turn on the TOSTOP bit while top was running, but I 19 * didn't really like the results. If you desire it, turn on the 20 * preprocessor variable "TOStop". --wnl 21 */ 22 23 #include <sys/ioctl.h> 24 #include <stdlib.h> 25 #include <string.h> 26 #include <termios.h> 27 #include <curses.h> 28 #include <termcap.h> 29 #include <unistd.h> 30 31 #include "screen.h" 32 #include "top.h" 33 34 int overstrike; 35 int screen_length; 36 int screen_width; 37 char ch_erase; 38 char ch_kill; 39 char smart_terminal; 40 static char termcap_buf[1024]; 41 static char string_buffer[1024]; 42 static char home[15]; 43 static char lower_left[15]; 44 char *clear_line; 45 static char *clear_screen; 46 char *clear_to_end; 47 char *cursor_motion; 48 static char *start_standout; 49 static char *end_standout; 50 static char *terminal_init; 51 static char *terminal_end; 52 53 static struct termios old_settings; 54 static struct termios new_settings; 55 static char is_a_terminal = false; 56 57 void 58 init_termcap(bool interactive) 59 { 60 char *bufptr; 61 char *PCptr; 62 char *term_name; 63 int status; 64 65 screen_width = 0; 66 screen_length = 0; 67 68 if (!interactive) 69 { 70 /* pretend we have a dumb terminal */ 71 smart_terminal = false; 72 return; 73 } 74 75 /* assume we have a smart terminal until proven otherwise */ 76 smart_terminal = true; 77 78 /* get the terminal name */ 79 term_name = getenv("TERM"); 80 81 /* if there is no TERM, assume it's a dumb terminal */ 82 /* patch courtesy of Sam Horrocks at telegraph.ics.uci.edu */ 83 if (term_name == NULL) 84 { 85 smart_terminal = false; 86 return; 87 } 88 89 /* now get the termcap entry */ 90 if ((status = tgetent(termcap_buf, term_name)) != 1) 91 { 92 if (status == -1) 93 { 94 fprintf(stderr, "%s: can't open termcap file\n", myname); 95 } 96 else 97 { 98 fprintf(stderr, "%s: no termcap entry for a `%s' terminal\n", 99 myname, term_name); 100 } 101 102 /* pretend it's dumb and proceed */ 103 smart_terminal = false; 104 return; 105 } 106 107 /* "hardcopy" immediately indicates a very stupid terminal */ 108 if (tgetflag("hc")) 109 { 110 smart_terminal = false; 111 return; 112 } 113 114 /* set up common terminal capabilities */ 115 if ((screen_length = tgetnum("li")) <= 0) 116 { 117 screen_length = smart_terminal = 0; 118 return; 119 } 120 121 /* screen_width is a little different */ 122 if ((screen_width = tgetnum("co")) == -1) 123 { 124 screen_width = 79; 125 } 126 else 127 { 128 screen_width -= 1; 129 } 130 131 /* terminals that overstrike need special attention */ 132 overstrike = tgetflag("os"); 133 134 /* initialize the pointer into the termcap string buffer */ 135 bufptr = string_buffer; 136 137 /* get "ce", clear to end */ 138 if (!overstrike) 139 { 140 clear_line = tgetstr("ce", &bufptr); 141 } 142 143 /* get necessary capabilities */ 144 if ((clear_screen = tgetstr("cl", &bufptr)) == NULL || 145 (cursor_motion = tgetstr("cm", &bufptr)) == NULL) 146 { 147 smart_terminal = false; 148 return; 149 } 150 151 /* get some more sophisticated stuff -- these are optional */ 152 clear_to_end = tgetstr("cd", &bufptr); 153 terminal_init = tgetstr("ti", &bufptr); 154 terminal_end = tgetstr("te", &bufptr); 155 start_standout = tgetstr("so", &bufptr); 156 end_standout = tgetstr("se", &bufptr); 157 158 /* pad character */ 159 PC = (PCptr = tgetstr("pc", &bufptr)) ? *PCptr : 0; 160 161 /* set convenience strings */ 162 strncpy(home, tgoto(cursor_motion, 0, 0), sizeof(home) - 1); 163 home[sizeof(home) - 1] = '\0'; 164 /* (lower_left is set in get_screensize) */ 165 166 /* get the actual screen size with an ioctl, if needed */ 167 /* This may change screen_width and screen_length, and it always 168 sets lower_left. */ 169 get_screensize(); 170 171 /* if stdout is not a terminal, pretend we are a dumb terminal */ 172 if (tcgetattr(STDOUT_FILENO, &old_settings) == -1) 173 { 174 smart_terminal = false; 175 } 176 } 177 178 void 179 init_screen(void) 180 { 181 /* get the old settings for safe keeping */ 182 if (tcgetattr(STDOUT_FILENO, &old_settings) != -1) 183 { 184 /* copy the settings so we can modify them */ 185 new_settings = old_settings; 186 187 /* turn off ICANON, character echo and tab expansion */ 188 new_settings.c_lflag &= ~(ICANON|ECHO); 189 new_settings.c_oflag &= ~(TAB3); 190 new_settings.c_cc[VMIN] = 1; 191 new_settings.c_cc[VTIME] = 0; 192 tcsetattr(STDOUT_FILENO, TCSADRAIN, &new_settings); 193 194 /* remember the erase and kill characters */ 195 ch_erase = old_settings.c_cc[VERASE]; 196 ch_kill = old_settings.c_cc[VKILL]; 197 198 /* remember that it really is a terminal */ 199 is_a_terminal = true; 200 201 /* send the termcap initialization string */ 202 putcap(terminal_init); 203 } 204 205 if (!is_a_terminal) 206 { 207 /* not a terminal at all---consider it dumb */ 208 smart_terminal = false; 209 } 210 } 211 212 void 213 end_screen(void) 214 { 215 /* move to the lower left, clear the line and send "te" */ 216 if (smart_terminal) 217 { 218 putcap(lower_left); 219 putcap(clear_line); 220 fflush(stdout); 221 putcap(terminal_end); 222 } 223 224 /* if we have settings to reset, then do so */ 225 if (is_a_terminal) 226 { 227 tcsetattr(STDOUT_FILENO, TCSADRAIN, &old_settings); 228 } 229 } 230 231 void 232 reinit_screen(void) 233 { 234 /* install our settings if it is a terminal */ 235 if (is_a_terminal) 236 { 237 tcsetattr(STDOUT_FILENO, TCSADRAIN, &new_settings); 238 } 239 240 /* send init string */ 241 if (smart_terminal) 242 { 243 putcap(terminal_init); 244 } 245 } 246 247 void 248 get_screensize(void) 249 { 250 struct winsize ws; 251 252 if (ioctl (1, TIOCGWINSZ, &ws) != -1) 253 { 254 if (ws.ws_row != 0) 255 { 256 screen_length = ws.ws_row; 257 } 258 if (ws.ws_col != 0) 259 { 260 screen_width = ws.ws_col - 1; 261 } 262 } 263 264 265 (void) strncpy(lower_left, tgoto(cursor_motion, 0, screen_length - 1), 266 sizeof(lower_left) - 1); 267 lower_left[sizeof(lower_left) - 1] = '\0'; 268 } 269 270 void 271 top_standout(const char *msg) 272 { 273 if (smart_terminal) 274 { 275 putcap(start_standout); 276 fputs(msg, stdout); 277 putcap(end_standout); 278 } 279 else 280 { 281 fputs(msg, stdout); 282 } 283 } 284 285 void 286 top_clear(void) 287 { 288 if (smart_terminal) 289 { 290 putcap(clear_screen); 291 } 292 } 293 294 int 295 clear_eol(int len) 296 { 297 if (smart_terminal && !overstrike && len > 0) 298 { 299 if (clear_line) 300 { 301 putcap(clear_line); 302 return(0); 303 } 304 else 305 { 306 while (len-- > 0) 307 { 308 putchar(' '); 309 } 310 return(1); 311 } 312 } 313 return(-1); 314 } 315