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