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