screen.c revision 65937
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: head/contrib/top/screen.c 65937 2000-09-16 19:36:18Z peter $ 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 53int putstdout(); 54 55int overstrike; 56int screen_length; 57int screen_width; 58char ch_erase; 59char ch_kill; 60char smart_terminal; 61char PC; 62char *tgetstr(); 63char *tgoto(); 64char termcap_buf[1024]; 65char string_buffer[1024]; 66char home[15]; 67char lower_left[15]; 68char *clear_line; 69char *clear_screen; 70char *clear_to_end; 71char *cursor_motion; 72char *start_standout; 73char *end_standout; 74char *terminal_init; 75char *terminal_end; 76 77#ifdef SGTTY 78static struct sgttyb old_settings; 79static struct sgttyb new_settings; 80#endif 81#ifdef TERMIO 82static struct termio old_settings; 83static struct termio new_settings; 84#endif 85#ifdef TERMIOS 86static struct termios old_settings; 87static struct termios new_settings; 88#endif 89static char is_a_terminal = No; 90#ifdef TOStop 91static int old_lword; 92static int new_lword; 93#endif 94 95#define STDIN 0 96#define STDOUT 1 97#define STDERR 2 98 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 238init_screen() 239 240{ 241 /* get the old settings for safe keeping */ 242#ifdef SGTTY 243 if (ioctl(STDOUT, TIOCGETP, &old_settings) != -1) 244 { 245 /* copy the settings so we can modify them */ 246 new_settings = old_settings; 247 248 /* turn on CBREAK and turn off character echo and tab expansion */ 249 new_settings.sg_flags |= CBREAK; 250 new_settings.sg_flags &= ~(ECHO|XTABS); 251 (void) ioctl(STDOUT, TIOCSETP, &new_settings); 252 253 /* remember the erase and kill characters */ 254 ch_erase = old_settings.sg_erase; 255 ch_kill = old_settings.sg_kill; 256 257#ifdef TOStop 258 /* get the local mode word */ 259 (void) ioctl(STDOUT, TIOCLGET, &old_lword); 260 261 /* modify it */ 262 new_lword = old_lword | LTOSTOP; 263 (void) ioctl(STDOUT, TIOCLSET, &new_lword); 264#endif 265 /* remember that it really is a terminal */ 266 is_a_terminal = Yes; 267 268 /* send the termcap initialization string */ 269 putcap(terminal_init); 270 } 271#endif 272#ifdef TERMIO 273 if (ioctl(STDOUT, TCGETA, &old_settings) != -1) 274 { 275 /* copy the settings so we can modify them */ 276 new_settings = old_settings; 277 278 /* turn off ICANON, character echo and tab expansion */ 279 new_settings.c_lflag &= ~(ICANON|ECHO); 280 new_settings.c_oflag &= ~(TAB3); 281 new_settings.c_cc[VMIN] = 1; 282 new_settings.c_cc[VTIME] = 0; 283 (void) ioctl(STDOUT, TCSETA, &new_settings); 284 285 /* remember the erase and kill characters */ 286 ch_erase = old_settings.c_cc[VERASE]; 287 ch_kill = old_settings.c_cc[VKILL]; 288 289 /* remember that it really is a terminal */ 290 is_a_terminal = Yes; 291 292 /* send the termcap initialization string */ 293 putcap(terminal_init); 294 } 295#endif 296#ifdef TERMIOS 297 if (tcgetattr(STDOUT, &old_settings) != -1) 298 { 299 /* copy the settings so we can modify them */ 300 new_settings = old_settings; 301 302 /* turn off ICANON, character echo and tab expansion */ 303 new_settings.c_lflag &= ~(ICANON|ECHO); 304 new_settings.c_oflag &= ~(TAB3); 305 new_settings.c_cc[VMIN] = 1; 306 new_settings.c_cc[VTIME] = 0; 307 (void) tcsetattr(STDOUT, TCSADRAIN, &new_settings); 308 309 /* remember the erase and kill characters */ 310 ch_erase = old_settings.c_cc[VERASE]; 311 ch_kill = old_settings.c_cc[VKILL]; 312 313 /* remember that it really is a terminal */ 314 is_a_terminal = Yes; 315 316 /* send the termcap initialization string */ 317 putcap(terminal_init); 318 } 319#endif 320 321 if (!is_a_terminal) 322 { 323 /* not a terminal at all---consider it dumb */ 324 smart_terminal = No; 325 } 326} 327 328end_screen() 329 330{ 331 /* move to the lower left, clear the line and send "te" */ 332 if (smart_terminal) 333 { 334 putcap(lower_left); 335 putcap(clear_line); 336 fflush(stdout); 337 putcap(terminal_end); 338 } 339 340 /* if we have settings to reset, then do so */ 341 if (is_a_terminal) 342 { 343#ifdef SGTTY 344 (void) ioctl(STDOUT, TIOCSETP, &old_settings); 345#ifdef TOStop 346 (void) ioctl(STDOUT, TIOCLSET, &old_lword); 347#endif 348#endif 349#ifdef TERMIO 350 (void) ioctl(STDOUT, TCSETA, &old_settings); 351#endif 352#ifdef TERMIOS 353 (void) tcsetattr(STDOUT, TCSADRAIN, &old_settings); 354#endif 355 } 356} 357 358reinit_screen() 359 360{ 361 /* install our settings if it is a terminal */ 362 if (is_a_terminal) 363 { 364#ifdef SGTTY 365 (void) ioctl(STDOUT, TIOCSETP, &new_settings); 366#ifdef TOStop 367 (void) ioctl(STDOUT, TIOCLSET, &new_lword); 368#endif 369#endif 370#ifdef TERMIO 371 (void) ioctl(STDOUT, TCSETA, &new_settings); 372#endif 373#ifdef TERMIOS 374 (void) tcsetattr(STDOUT, TCSADRAIN, &new_settings); 375#endif 376 } 377 378 /* send init string */ 379 if (smart_terminal) 380 { 381 putcap(terminal_init); 382 } 383} 384 385get_screensize() 386 387{ 388 389#ifdef TIOCGWINSZ 390 391 struct winsize ws; 392 393 if (ioctl (1, TIOCGWINSZ, &ws) != -1) 394 { 395 if (ws.ws_row != 0) 396 { 397 screen_length = ws.ws_row; 398 } 399 if (ws.ws_col != 0) 400 { 401 screen_width = ws.ws_col - 1; 402 } 403 } 404 405#else 406#ifdef TIOCGSIZE 407 408 struct ttysize ts; 409 410 if (ioctl (1, TIOCGSIZE, &ts) != -1) 411 { 412 if (ts.ts_lines != 0) 413 { 414 screen_length = ts.ts_lines; 415 } 416 if (ts.ts_cols != 0) 417 { 418 screen_width = ts.ts_cols - 1; 419 } 420 } 421 422#endif /* TIOCGSIZE */ 423#endif /* TIOCGWINSZ */ 424 425 (void) strncpy(lower_left, tgoto(cursor_motion, 0, screen_length - 1), 426 sizeof(lower_left) - 1); 427 lower_left[sizeof(lower_left) - 1] = '\0'; 428} 429 430standout(msg) 431 432char *msg; 433 434{ 435 if (smart_terminal) 436 { 437 putcap(start_standout); 438 fputs(msg, stdout); 439 putcap(end_standout); 440 } 441 else 442 { 443 fputs(msg, stdout); 444 } 445} 446 447clear() 448 449{ 450 if (smart_terminal) 451 { 452 putcap(clear_screen); 453 } 454} 455 456clear_eol(len) 457 458int len; 459 460{ 461 if (smart_terminal && !overstrike && len > 0) 462 { 463 if (clear_line) 464 { 465 putcap(clear_line); 466 return(0); 467 } 468 else 469 { 470 while (len-- > 0) 471 { 472 putchar(' '); 473 } 474 return(1); 475 } 476 } 477 return(-1); 478} 479 480go_home() 481 482{ 483 if (smart_terminal) 484 { 485 putcap(home); 486 } 487} 488 489/* This has to be defined as a subroutine for tputs (instead of a macro) */ 490 491putstdout(ch) 492 493char ch; 494 495{ 496 putchar(ch); 497} 498 499