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: releng/11.0/contrib/top/screen.c 300395 2016-05-22 04:17:00Z ngie $ 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 "os.h" 24#include "top.h" 25 26#include <sys/ioctl.h> 27#ifdef CBREAK 28# include <sgtty.h> 29# define SGTTY 30#else 31# ifdef TCGETA 32# define TERMIO 33# include <termio.h> 34# else 35# define TERMIOS 36# include <termios.h> 37# endif 38#endif 39#if defined(TERMIO) || defined(TERMIOS) 40# ifndef TAB3 41# ifdef OXTABS 42# define TAB3 OXTABS 43# else 44# define TAB3 0 45# endif 46# endif 47#endif 48#include "screen.h" 49#include "boolean.h" 50 51extern char *myname; 52 53 54int overstrike; 55int screen_length; 56int screen_width; 57char ch_erase; 58char ch_kill; 59char smart_terminal; 60char PC; 61char *tgetstr(); 62char *tgoto(); 63char termcap_buf[1024]; 64char string_buffer[1024]; 65char home[15]; 66char lower_left[15]; 67char *clear_line; 68char *clear_screen; 69char *clear_to_end; 70char *cursor_motion; 71char *start_standout; 72char *end_standout; 73char *terminal_init; 74char *terminal_end; 75 76#ifdef SGTTY 77static struct sgttyb old_settings; 78static struct sgttyb new_settings; 79#endif 80#ifdef TERMIO 81static struct termio old_settings; 82static struct termio new_settings; 83#endif 84#ifdef TERMIOS 85static struct termios old_settings; 86static struct termios new_settings; 87#endif 88static char is_a_terminal = No; 89#ifdef TOStop 90static int old_lword; 91static int new_lword; 92#endif 93 94#define STDIN 0 95#define STDOUT 1 96#define STDERR 2 97 98void 99init_termcap(interactive) 100 101int interactive; 102 103{ 104 char *bufptr; 105 char *PCptr; 106 char *term_name; 107 char *getenv(); 108 int status; 109 110 /* set defaults in case we aren't smart */ 111 screen_width = MAX_COLS; 112 screen_length = 0; 113 114 if (!interactive) 115 { 116 /* pretend we have a dumb terminal */ 117 smart_terminal = No; 118 return; 119 } 120 121 /* assume we have a smart terminal until proven otherwise */ 122 smart_terminal = Yes; 123 124 /* get the terminal name */ 125 term_name = getenv("TERM"); 126 127 /* if there is no TERM, assume it's a dumb terminal */ 128 /* patch courtesy of Sam Horrocks at telegraph.ics.uci.edu */ 129 if (term_name == NULL) 130 { 131 smart_terminal = No; 132 return; 133 } 134 135 /* now get the termcap entry */ 136 if ((status = tgetent(termcap_buf, term_name)) != 1) 137 { 138 if (status == -1) 139 { 140 fprintf(stderr, "%s: can't open termcap file\n", myname); 141 } 142 else 143 { 144 fprintf(stderr, "%s: no termcap entry for a `%s' terminal\n", 145 myname, term_name); 146 } 147 148 /* pretend it's dumb and proceed */ 149 smart_terminal = No; 150 return; 151 } 152 153 /* "hardcopy" immediately indicates a very stupid terminal */ 154 if (tgetflag("hc")) 155 { 156 smart_terminal = No; 157 return; 158 } 159 160 /* set up common terminal capabilities */ 161 if ((screen_length = tgetnum("li")) <= 0) 162 { 163 screen_length = smart_terminal = 0; 164 return; 165 } 166 167 /* screen_width is a little different */ 168 if ((screen_width = tgetnum("co")) == -1) 169 { 170 screen_width = 79; 171 } 172 else 173 { 174 screen_width -= 1; 175 } 176 177 /* terminals that overstrike need special attention */ 178 overstrike = tgetflag("os"); 179 180 /* initialize the pointer into the termcap string buffer */ 181 bufptr = string_buffer; 182 183 /* get "ce", clear to end */ 184 if (!overstrike) 185 { 186 clear_line = tgetstr("ce", &bufptr); 187 } 188 189 /* get necessary capabilities */ 190 if ((clear_screen = tgetstr("cl", &bufptr)) == NULL || 191 (cursor_motion = tgetstr("cm", &bufptr)) == NULL) 192 { 193 smart_terminal = No; 194 return; 195 } 196 197 /* get some more sophisticated stuff -- these are optional */ 198 clear_to_end = tgetstr("cd", &bufptr); 199 terminal_init = tgetstr("ti", &bufptr); 200 terminal_end = tgetstr("te", &bufptr); 201 start_standout = tgetstr("so", &bufptr); 202 end_standout = tgetstr("se", &bufptr); 203 204 /* pad character */ 205 PC = (PCptr = tgetstr("pc", &bufptr)) ? *PCptr : 0; 206 207 /* set convenience strings */ 208 (void) strncpy(home, tgoto(cursor_motion, 0, 0), sizeof(home) - 1); 209 home[sizeof(home) - 1] = '\0'; 210 /* (lower_left is set in get_screensize) */ 211 212 /* get the actual screen size with an ioctl, if needed */ 213 /* This may change screen_width and screen_length, and it always 214 sets lower_left. */ 215 get_screensize(); 216 217 /* if stdout is not a terminal, pretend we are a dumb terminal */ 218#ifdef SGTTY 219 if (ioctl(STDOUT, TIOCGETP, &old_settings) == -1) 220 { 221 smart_terminal = No; 222 } 223#endif 224#ifdef TERMIO 225 if (ioctl(STDOUT, TCGETA, &old_settings) == -1) 226 { 227 smart_terminal = No; 228 } 229#endif 230#ifdef TERMIOS 231 if (tcgetattr(STDOUT, &old_settings) == -1) 232 { 233 smart_terminal = No; 234 } 235#endif 236} 237 238void 239init_screen() 240 241{ 242 /* get the old settings for safe keeping */ 243#ifdef SGTTY 244 if (ioctl(STDOUT, TIOCGETP, &old_settings) != -1) 245 { 246 /* copy the settings so we can modify them */ 247 new_settings = old_settings; 248 249 /* turn on CBREAK and turn off character echo and tab expansion */ 250 new_settings.sg_flags |= CBREAK; 251 new_settings.sg_flags &= ~(ECHO|XTABS); 252 (void) ioctl(STDOUT, TIOCSETP, &new_settings); 253 254 /* remember the erase and kill characters */ 255 ch_erase = old_settings.sg_erase; 256 ch_kill = old_settings.sg_kill; 257 258#ifdef TOStop 259 /* get the local mode word */ 260 (void) ioctl(STDOUT, TIOCLGET, &old_lword); 261 262 /* modify it */ 263 new_lword = old_lword | LTOSTOP; 264 (void) ioctl(STDOUT, TIOCLSET, &new_lword); 265#endif 266 /* remember that it really is a terminal */ 267 is_a_terminal = Yes; 268 269 /* send the termcap initialization string */ 270 putcap(terminal_init); 271 } 272#endif 273#ifdef TERMIO 274 if (ioctl(STDOUT, TCGETA, &old_settings) != -1) 275 { 276 /* copy the settings so we can modify them */ 277 new_settings = old_settings; 278 279 /* turn off ICANON, character echo and tab expansion */ 280 new_settings.c_lflag &= ~(ICANON|ECHO); 281 new_settings.c_oflag &= ~(TAB3); 282 new_settings.c_cc[VMIN] = 1; 283 new_settings.c_cc[VTIME] = 0; 284 (void) ioctl(STDOUT, TCSETA, &new_settings); 285 286 /* remember the erase and kill characters */ 287 ch_erase = old_settings.c_cc[VERASE]; 288 ch_kill = old_settings.c_cc[VKILL]; 289 290 /* remember that it really is a terminal */ 291 is_a_terminal = Yes; 292 293 /* send the termcap initialization string */ 294 putcap(terminal_init); 295 } 296#endif 297#ifdef TERMIOS 298 if (tcgetattr(STDOUT, &old_settings) != -1) 299 { 300 /* copy the settings so we can modify them */ 301 new_settings = old_settings; 302 303 /* turn off ICANON, character echo and tab expansion */ 304 new_settings.c_lflag &= ~(ICANON|ECHO); 305 new_settings.c_oflag &= ~(TAB3); 306 new_settings.c_cc[VMIN] = 1; 307 new_settings.c_cc[VTIME] = 0; 308 (void) tcsetattr(STDOUT, TCSADRAIN, &new_settings); 309 310 /* remember the erase and kill characters */ 311 ch_erase = old_settings.c_cc[VERASE]; 312 ch_kill = old_settings.c_cc[VKILL]; 313 314 /* remember that it really is a terminal */ 315 is_a_terminal = Yes; 316 317 /* send the termcap initialization string */ 318 putcap(terminal_init); 319 } 320#endif 321 322 if (!is_a_terminal) 323 { 324 /* not a terminal at all---consider it dumb */ 325 smart_terminal = No; 326 } 327} 328 329void 330end_screen() 331 332{ 333 /* move to the lower left, clear the line and send "te" */ 334 if (smart_terminal) 335 { 336 putcap(lower_left); 337 putcap(clear_line); 338 fflush(stdout); 339 putcap(terminal_end); 340 } 341 342 /* if we have settings to reset, then do so */ 343 if (is_a_terminal) 344 { 345#ifdef SGTTY 346 (void) ioctl(STDOUT, TIOCSETP, &old_settings); 347#ifdef TOStop 348 (void) ioctl(STDOUT, TIOCLSET, &old_lword); 349#endif 350#endif 351#ifdef TERMIO 352 (void) ioctl(STDOUT, TCSETA, &old_settings); 353#endif 354#ifdef TERMIOS 355 (void) tcsetattr(STDOUT, TCSADRAIN, &old_settings); 356#endif 357 } 358} 359 360void 361reinit_screen() 362 363{ 364 /* install our settings if it is a terminal */ 365 if (is_a_terminal) 366 { 367#ifdef SGTTY 368 (void) ioctl(STDOUT, TIOCSETP, &new_settings); 369#ifdef TOStop 370 (void) ioctl(STDOUT, TIOCLSET, &new_lword); 371#endif 372#endif 373#ifdef TERMIO 374 (void) ioctl(STDOUT, TCSETA, &new_settings); 375#endif 376#ifdef TERMIOS 377 (void) tcsetattr(STDOUT, TCSADRAIN, &new_settings); 378#endif 379 } 380 381 /* send init string */ 382 if (smart_terminal) 383 { 384 putcap(terminal_init); 385 } 386} 387 388void 389get_screensize() 390 391{ 392 393#ifdef TIOCGWINSZ 394 395 struct winsize ws; 396 397 if (ioctl (1, TIOCGWINSZ, &ws) != -1) 398 { 399 if (ws.ws_row != 0) 400 { 401 screen_length = ws.ws_row; 402 } 403 if (ws.ws_col != 0) 404 { 405 screen_width = ws.ws_col - 1; 406 } 407 } 408 409#else 410#ifdef TIOCGSIZE 411 412 struct ttysize ts; 413 414 if (ioctl (1, TIOCGSIZE, &ts) != -1) 415 { 416 if (ts.ts_lines != 0) 417 { 418 screen_length = ts.ts_lines; 419 } 420 if (ts.ts_cols != 0) 421 { 422 screen_width = ts.ts_cols - 1; 423 } 424 } 425 426#endif /* TIOCGSIZE */ 427#endif /* TIOCGWINSZ */ 428 429 (void) strncpy(lower_left, tgoto(cursor_motion, 0, screen_length - 1), 430 sizeof(lower_left) - 1); 431 lower_left[sizeof(lower_left) - 1] = '\0'; 432} 433 434void 435standout(msg) 436 437char *msg; 438 439{ 440 if (smart_terminal) 441 { 442 putcap(start_standout); 443 fputs(msg, stdout); 444 putcap(end_standout); 445 } 446 else 447 { 448 fputs(msg, stdout); 449 } 450} 451 452void 453clear() 454 455{ 456 if (smart_terminal) 457 { 458 putcap(clear_screen); 459 } 460} 461 462int 463clear_eol(len) 464 465int len; 466 467{ 468 if (smart_terminal && !overstrike && len > 0) 469 { 470 if (clear_line) 471 { 472 putcap(clear_line); 473 return(0); 474 } 475 else 476 { 477 while (len-- > 0) 478 { 479 putchar(' '); 480 } 481 return(1); 482 } 483 } 484 return(-1); 485} 486 487void 488go_home() 489 490{ 491 if (smart_terminal) 492 { 493 putcap(home); 494 } 495} 496 497/* This has to be defined as a subroutine for tputs (instead of a macro) */ 498 499void 500putstdout(ch) 501 502char ch; 503 504{ 505 putchar(ch); 506} 507 508