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