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