screen.c revision 210386
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 210386 2010-07-22 18:52:29Z rpaulo $ 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 99void 100init_termcap(interactive) 101 102int interactive; 103 104{ 105 char *bufptr; 106 char *PCptr; 107 char *term_name; 108 char *getenv(); 109 int status; 110 111 /* set defaults in case we aren't smart */ 112 screen_width = MAX_COLS; 113 screen_length = 0; 114 115 if (!interactive) 116 { 117 /* pretend we have a dumb terminal */ 118 smart_terminal = No; 119 return; 120 } 121 122 /* assume we have a smart terminal until proven otherwise */ 123 smart_terminal = Yes; 124 125 /* get the terminal name */ 126 term_name = getenv("TERM"); 127 128 /* if there is no TERM, assume it's a dumb terminal */ 129 /* patch courtesy of Sam Horrocks at telegraph.ics.uci.edu */ 130 if (term_name == NULL) 131 { 132 smart_terminal = No; 133 return; 134 } 135 136 /* now get the termcap entry */ 137 if ((status = tgetent(termcap_buf, term_name)) != 1) 138 { 139 if (status == -1) 140 { 141 fprintf(stderr, "%s: can't open termcap file\n", myname); 142 } 143 else 144 { 145 fprintf(stderr, "%s: no termcap entry for a `%s' terminal\n", 146 myname, term_name); 147 } 148 149 /* pretend it's dumb and proceed */ 150 smart_terminal = No; 151 return; 152 } 153 154 /* "hardcopy" immediately indicates a very stupid terminal */ 155 if (tgetflag("hc")) 156 { 157 smart_terminal = No; 158 return; 159 } 160 161 /* set up common terminal capabilities */ 162 if ((screen_length = tgetnum("li")) <= 0) 163 { 164 screen_length = smart_terminal = 0; 165 return; 166 } 167 168 /* screen_width is a little different */ 169 if ((screen_width = tgetnum("co")) == -1) 170 { 171 screen_width = 79; 172 } 173 else 174 { 175 screen_width -= 1; 176 } 177 178 /* terminals that overstrike need special attention */ 179 overstrike = tgetflag("os"); 180 181 /* initialize the pointer into the termcap string buffer */ 182 bufptr = string_buffer; 183 184 /* get "ce", clear to end */ 185 if (!overstrike) 186 { 187 clear_line = tgetstr("ce", &bufptr); 188 } 189 190 /* get necessary capabilities */ 191 if ((clear_screen = tgetstr("cl", &bufptr)) == NULL || 192 (cursor_motion = tgetstr("cm", &bufptr)) == NULL) 193 { 194 smart_terminal = No; 195 return; 196 } 197 198 /* get some more sophisticated stuff -- these are optional */ 199 clear_to_end = tgetstr("cd", &bufptr); 200 terminal_init = tgetstr("ti", &bufptr); 201 terminal_end = tgetstr("te", &bufptr); 202 start_standout = tgetstr("so", &bufptr); 203 end_standout = tgetstr("se", &bufptr); 204 205 /* pad character */ 206 PC = (PCptr = tgetstr("pc", &bufptr)) ? *PCptr : 0; 207 208 /* set convenience strings */ 209 (void) strncpy(home, tgoto(cursor_motion, 0, 0), sizeof(home) - 1); 210 home[sizeof(home) - 1] = '\0'; 211 /* (lower_left is set in get_screensize) */ 212 213 /* get the actual screen size with an ioctl, if needed */ 214 /* This may change screen_width and screen_length, and it always 215 sets lower_left. */ 216 get_screensize(); 217 218 /* if stdout is not a terminal, pretend we are a dumb terminal */ 219#ifdef SGTTY 220 if (ioctl(STDOUT, TIOCGETP, &old_settings) == -1) 221 { 222 smart_terminal = No; 223 } 224#endif 225#ifdef TERMIO 226 if (ioctl(STDOUT, TCGETA, &old_settings) == -1) 227 { 228 smart_terminal = No; 229 } 230#endif 231#ifdef TERMIOS 232 if (tcgetattr(STDOUT, &old_settings) == -1) 233 { 234 smart_terminal = No; 235 } 236#endif 237} 238 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 329end_screen() 330 331{ 332 /* move to the lower left, clear the line and send "te" */ 333 if (smart_terminal) 334 { 335 putcap(lower_left); 336 putcap(clear_line); 337 fflush(stdout); 338 putcap(terminal_end); 339 } 340 341 /* if we have settings to reset, then do so */ 342 if (is_a_terminal) 343 { 344#ifdef SGTTY 345 (void) ioctl(STDOUT, TIOCSETP, &old_settings); 346#ifdef TOStop 347 (void) ioctl(STDOUT, TIOCLSET, &old_lword); 348#endif 349#endif 350#ifdef TERMIO 351 (void) ioctl(STDOUT, TCSETA, &old_settings); 352#endif 353#ifdef TERMIOS 354 (void) tcsetattr(STDOUT, TCSADRAIN, &old_settings); 355#endif 356 } 357} 358 359reinit_screen() 360 361{ 362 /* install our settings if it is a terminal */ 363 if (is_a_terminal) 364 { 365#ifdef SGTTY 366 (void) ioctl(STDOUT, TIOCSETP, &new_settings); 367#ifdef TOStop 368 (void) ioctl(STDOUT, TIOCLSET, &new_lword); 369#endif 370#endif 371#ifdef TERMIO 372 (void) ioctl(STDOUT, TCSETA, &new_settings); 373#endif 374#ifdef TERMIOS 375 (void) tcsetattr(STDOUT, TCSADRAIN, &new_settings); 376#endif 377 } 378 379 /* send init string */ 380 if (smart_terminal) 381 { 382 putcap(terminal_init); 383 } 384} 385 386get_screensize() 387 388{ 389 390#ifdef TIOCGWINSZ 391 392 struct winsize ws; 393 394 if (ioctl (1, TIOCGWINSZ, &ws) != -1) 395 { 396 if (ws.ws_row != 0) 397 { 398 screen_length = ws.ws_row; 399 } 400 if (ws.ws_col != 0) 401 { 402 screen_width = ws.ws_col - 1; 403 } 404 } 405 406#else 407#ifdef TIOCGSIZE 408 409 struct ttysize ts; 410 411 if (ioctl (1, TIOCGSIZE, &ts) != -1) 412 { 413 if (ts.ts_lines != 0) 414 { 415 screen_length = ts.ts_lines; 416 } 417 if (ts.ts_cols != 0) 418 { 419 screen_width = ts.ts_cols - 1; 420 } 421 } 422 423#endif /* TIOCGSIZE */ 424#endif /* TIOCGWINSZ */ 425 426 (void) strncpy(lower_left, tgoto(cursor_motion, 0, screen_length - 1), 427 sizeof(lower_left) - 1); 428 lower_left[sizeof(lower_left) - 1] = '\0'; 429} 430 431standout(msg) 432 433char *msg; 434 435{ 436 if (smart_terminal) 437 { 438 putcap(start_standout); 439 fputs(msg, stdout); 440 putcap(end_standout); 441 } 442 else 443 { 444 fputs(msg, stdout); 445 } 446} 447 448clear() 449 450{ 451 if (smart_terminal) 452 { 453 putcap(clear_screen); 454 } 455} 456 457clear_eol(len) 458 459int len; 460 461{ 462 if (smart_terminal && !overstrike && len > 0) 463 { 464 if (clear_line) 465 { 466 putcap(clear_line); 467 return(0); 468 } 469 else 470 { 471 while (len-- > 0) 472 { 473 putchar(' '); 474 } 475 return(1); 476 } 477 } 478 return(-1); 479} 480 481go_home() 482 483{ 484 if (smart_terminal) 485 { 486 putcap(home); 487 } 488} 489 490/* This has to be defined as a subroutine for tputs (instead of a macro) */ 491 492putstdout(ch) 493 494char ch; 495 496{ 497 putchar(ch); 498} 499 500