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 "top.h" 24 25 #include <sys/ioctl.h> 26 #include <stdlib.h> 27 #include <string.h> 28 #define TERMIOS 29 #include <termios.h> 30 #include <curses.h> 31 #include <termcap.h> 32 #include "screen.h" 33 #include "boolean.h" 34 35 int overstrike; 36 int screen_length; 37 int screen_width; 38 char ch_erase; 39 char ch_kill; 40 char smart_terminal; 41 char PC; 42 static char termcap_buf[1024]; 43 static char string_buffer[1024]; 44 static char home[15]; 45 static char lower_left[15]; 46 char *clear_line; 47 static char *clear_screen; 48 char *clear_to_end; 49 char *cursor_motion; 50 static char *start_standout; 51 static char *end_standout; 52 static char *terminal_init; 53 static char *terminal_end; 54 55 static struct termios old_settings; 56 static struct termios new_settings; 57 static char is_a_terminal = No; 58 59 #define STDIN 0 60 #define STDOUT 1 61 #define STDERR 2 62 63 void 64 init_termcap(interactive) 65 66 int interactive; 67 68 { 69 char *bufptr; 70 char *PCptr; 71 char *term_name; 72 int status; 73 74 /* set defaults in case we aren't smart */ 75 screen_width = MAX_COLS; 76 screen_length = 0; 77 78 if (!interactive) 79 { 80 /* pretend we have a dumb terminal */ 81 smart_terminal = No; 82 return; 83 } 84 85 /* assume we have a smart terminal until proven otherwise */ 86 smart_terminal = Yes; 87 88 /* get the terminal name */ 89 term_name = getenv("TERM"); 90 91 /* if there is no TERM, assume it's a dumb terminal */ 92 /* patch courtesy of Sam Horrocks at telegraph.ics.uci.edu */ 93 if (term_name == NULL) 94 { 95 smart_terminal = No; 96 return; 97 } 98 99 /* now get the termcap entry */ 100 if ((status = tgetent(termcap_buf, term_name)) != 1) 101 { 102 if (status == -1) 103 { 104 fprintf(stderr, "%s: can't open termcap file\n", myname); 105 } 106 else 107 { 108 fprintf(stderr, "%s: no termcap entry for a `%s' terminal\n", 109 myname, term_name); 110 } 111 112 /* pretend it's dumb and proceed */ 113 smart_terminal = No; 114 return; 115 } 116 117 /* "hardcopy" immediately indicates a very stupid terminal */ 118 if (tgetflag("hc")) 119 { 120 smart_terminal = No; 121 return; 122 } 123 124 /* set up common terminal capabilities */ 125 if ((screen_length = tgetnum("li")) <= 0) 126 { 127 screen_length = smart_terminal = 0; 128 return; 129 } 130 131 /* screen_width is a little different */ 132 if ((screen_width = tgetnum("co")) == -1) 133 { 134 screen_width = 79; 135 } 136 else 137 { 138 screen_width -= 1; 139 } 140 141 /* terminals that overstrike need special attention */ 142 overstrike = tgetflag("os"); 143 144 /* initialize the pointer into the termcap string buffer */ 145 bufptr = string_buffer; 146 147 /* get "ce", clear to end */ 148 if (!overstrike) 149 { 150 clear_line = tgetstr("ce", &bufptr); 151 } 152 153 /* get necessary capabilities */ 154 if ((clear_screen = tgetstr("cl", &bufptr)) == NULL || 155 (cursor_motion = tgetstr("cm", &bufptr)) == NULL) 156 { 157 smart_terminal = No; 158 return; 159 } 160 161 /* get some more sophisticated stuff -- these are optional */ 162 clear_to_end = tgetstr("cd", &bufptr); 163 terminal_init = tgetstr("ti", &bufptr); 164 terminal_end = tgetstr("te", &bufptr); 165 start_standout = tgetstr("so", &bufptr); 166 end_standout = tgetstr("se", &bufptr); 167 168 /* pad character */ 169 PC = (PCptr = tgetstr("pc", &bufptr)) ? *PCptr : 0; 170 171 /* set convenience strings */ 172 (void) strncpy(home, tgoto(cursor_motion, 0, 0), sizeof(home) - 1); 173 home[sizeof(home) - 1] = '\0'; 174 /* (lower_left is set in get_screensize) */ 175 176 /* get the actual screen size with an ioctl, if needed */ 177 /* This may change screen_width and screen_length, and it always 178 sets lower_left. */ 179 get_screensize(); 180 181 /* if stdout is not a terminal, pretend we are a dumb terminal */ 182 if (tcgetattr(STDOUT, &old_settings) == -1) 183 { 184 smart_terminal = No; 185 } 186 } 187 188 void 189 init_screen() 190 191 { 192 /* get the old settings for safe keeping */ 193 if (tcgetattr(STDOUT, &old_settings) != -1) 194 { 195 /* copy the settings so we can modify them */ 196 new_settings = old_settings; 197 198 /* turn off ICANON, character echo and tab expansion */ 199 new_settings.c_lflag &= ~(ICANON|ECHO); 200 new_settings.c_oflag &= ~(TAB3); 201 new_settings.c_cc[VMIN] = 1; 202 new_settings.c_cc[VTIME] = 0; 203 (void) tcsetattr(STDOUT, TCSADRAIN, &new_settings); 204 205 /* remember the erase and kill characters */ 206 ch_erase = old_settings.c_cc[VERASE]; 207 ch_kill = old_settings.c_cc[VKILL]; 208 209 /* remember that it really is a terminal */ 210 is_a_terminal = Yes; 211 212 /* send the termcap initialization string */ 213 putcap(terminal_init); 214 } 215 216 if (!is_a_terminal) 217 { 218 /* not a terminal at all---consider it dumb */ 219 smart_terminal = No; 220 } 221 } 222 223 void 224 end_screen() 225 226 { 227 /* move to the lower left, clear the line and send "te" */ 228 if (smart_terminal) 229 { 230 putcap(lower_left); 231 putcap(clear_line); 232 fflush(stdout); 233 putcap(terminal_end); 234 } 235 236 /* if we have settings to reset, then do so */ 237 if (is_a_terminal) 238 { 239 (void) tcsetattr(STDOUT, TCSADRAIN, &old_settings); 240 } 241 } 242 243 void 244 reinit_screen() 245 246 { 247 /* install our settings if it is a terminal */ 248 if (is_a_terminal) 249 { 250 (void) tcsetattr(STDOUT, TCSADRAIN, &new_settings); 251 } 252 253 /* send init string */ 254 if (smart_terminal) 255 { 256 putcap(terminal_init); 257 } 258 } 259 260 void 261 get_screensize() 262 263 { 264 265 266 struct winsize ws; 267 268 if (ioctl (1, TIOCGWINSZ, &ws) != -1) 269 { 270 if (ws.ws_row != 0) 271 { 272 screen_length = ws.ws_row; 273 } 274 if (ws.ws_col != 0) 275 { 276 screen_width = ws.ws_col - 1; 277 } 278 } 279 280 281 (void) strncpy(lower_left, tgoto(cursor_motion, 0, screen_length - 1), 282 sizeof(lower_left) - 1); 283 lower_left[sizeof(lower_left) - 1] = '\0'; 284 } 285 286 void 287 top_standout(char *msg) 288 { 289 if (smart_terminal) 290 { 291 putcap(start_standout); 292 fputs(msg, stdout); 293 putcap(end_standout); 294 } 295 else 296 { 297 fputs(msg, stdout); 298 } 299 } 300 301 void 302 top_clear() 303 { 304 if (smart_terminal) 305 { 306 putcap(clear_screen); 307 } 308 } 309 310 int 311 clear_eol(int len) 312 { 313 if (smart_terminal && !overstrike && len > 0) 314 { 315 if (clear_line) 316 { 317 putcap(clear_line); 318 return(0); 319 } 320 else 321 { 322 while (len-- > 0) 323 { 324 putchar(' '); 325 } 326 return(1); 327 } 328 } 329 return(-1); 330 } 331 332 void 333 go_home() 334 335 { 336 if (smart_terminal) 337 { 338 putcap(home); 339 } 340 } 341 342 /* This has to be defined as a subroutine for tputs (instead of a macro) */ 343 344 int 345 putstdout(int ch) 346 { 347 return putchar(ch); 348 } 349