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